初识scrapy框架(二)

  在初识scrapy框架(一)里,对scrapy爬取数据有了一定的了解,下面将介绍爬某招聘网站

信息的案例,并以此说明代码要注意的坑,以及书写代码要注意的一些规范。

创建爬虫项目:scrapy startproject Tencent_recruit

创建爬虫文件:scrapy genspider recruit 'URL'

明确爬虫目标:在 items 文件里添加要爬取的目标:

 1 import scrapy
 2 
 3 
 4 class TencentRecruitItem(scrapy.Item):
 5     # define the fields for your item here like:
 6     # name = scrapy.Field()
 7     position_name = scrapy.Field()
 8     position_category = scrapy.Field()
 9     position_number = scrapy.Field()
10     position_place = scrapy.Field()
11     position_link = scrapy.Field()
12     release_time = scrapy.Field()
13 
14 
15 class DetailRecruitItem(scrapy.Item):
16     work_duty = scrapy.Field()
17     work_request = scrapy.Field()
18     position_name = scrapy.Field()

编写爬虫文件:

 1 import scrapy
 2 from Tencent_recruit.items import TencentRecruitItem, DetailRecruitItem
 3 
 4 
 5 class RecruitSpider(scrapy.Spider):
 6     name = 'recruit'
 7     allowed_domains = ['hr.tencent.com']
 8     start_urls = ['https://hr.tencent.com/position.php']
 9     base_urls = 'https://hr.tencent.com/'
10 
11     def parse(self, response):
12         print('=================================================')
13         node_list = response.xpath('//tr[@class="even"] | //tr[@class="odd"]')
14         next_page = response.xpath('//*[@id="next"]/@href').extract_first()
15         print(type(next_page))
16         for node in node_list:
17             item = TencentRecruitItem()
18             item['position_name'] = node.xpath('./td[1]/a/text()').extract_first()
19             item['position_category'] = node.xpath('./td[2]/text()').extract_first()
20             item['position_number'] = node.xpath('./td[3]/text()').extract_first()
21             item['position_place'] = node.xpath('./td[4]/text()').extract_first()
22             item['position_link'] = node.xpath('./td[1]/a/@href').extract_first()
23             item['release_time'] = node.xpath('./td[5]/text()').extract_first()
24             yield item
25             yield scrapy.Request(url=self.base_urls + item['position_link'], callback=self.detail)
26         next_url = self.base_urls + next_page
27         yield scrapy.Request(url=next_url, callback=self.parse)
28 
29     def detail(self, response):
30         item = DetailRecruitItem()
31         print('detail正在执行')
32         item['position_name'] = response.xpath('//*[@id="sharetitle"]/text()').extract_first()
33         result = response.xpath('//ul[@class="squareli"]')
34         duty = result[0]
35         req = result[1]
36         item['work_duty'] = ''.join(duty.xpath('./li/text()').extract())
37         item['work_request'] = ''.join(req.xpath('./li/text()').extract())
38         yield item

  这里有一行代码高亮加粗显示,一定要注意这里,实例一定要在for循环里面,如果在外边会使得

数据可能产生错误!!在yield调用详情页函数detail时,这个命令是交给引擎,引擎会交给调度器入列,

如果使用meta参数(传参方法:meta={"item": item} )将item传给detail函数,则传入的item就会是

最后一次请求的item,即所有调用detail 函数传入的item一样。在detail函数里取用item时可以使用下面

的代码:item = response.meta["item"] .

  这里还有一个坑:字符串的拼接。相信有很多跟我一样的初学者,自己在写代码时不是很注意URL

的拼接,next_url = self.base_urls + next_page 这样可以访问,如果是next_page + self.base_urls ,就

会中断的代码的执行。我在写的时候就遇到这样的问题,一直以为detail函数没有执行,但是又不知道

yield有什么问题(感觉那一句没有问题),浪费两个小时,才问潭州的空山老师,结果瞬间尴尬。上面

的问题在于,如果是后者,那么url= 'baidu.com' + 'https://' 这种。

编写管道文件:

 1 import json
 2 from Tencent_recruit.items import TencentRecruitItem, DetailRecruitItem
 3 
 4 
 5 class TencentRecruitPipeline(object):
 6 
 7     def open_spider(self, spider):
 8         self.mg = open('tencent.json', 'w', encoding='utf-8')
 9 
10     def process_item(self, item, spider):
11         print('正在执行类:TencentRecruitPipeline')
12         if isinstance(item, TencentRecruitItem):
13             print('T')
14             content = json.dumps(dict(item), ensure_ascii=False) + "\n"
15             self.mg.write(content)
16         return item
17 
18     def close_spider(self, spider):
19         self.mg.close()
20 
21 
22 class DetailRecruitPipeline(object):
23 
24     def open_spider(self, spider):
25         self.file = open('detail.json', 'w', encoding='utf-8')
26 
27     def process_item(self, item, spider):
28         print('正在执行类:DetailRecruitPipeline')
29         if isinstance(item, DetailRecruitItem):
30             print('T')
31             content = json.dumps(dict(item), ensure_ascii=False) + "\n"
32             self.file.write(content)
33         return item
34 
35     def close_spider(self, spider):
36         self.file.close()

  这里和爬虫文件一致,我们讲数据存为两个json文件。类里面的三个方法名字都是框架的

标准名,不要乱写,会报错的!!一定要注意 return 的缩进问题,如果return 在 if 里面可能会

让你取不到数据!!如果一想用一个类保存数据也是可以的,只需要简单修改一下代码即可。

配置管道文件:

  在settings.py 文件里设置 ITEM_PIPELINES 和 USER_AGENT

  USER_AGENT这个在文件前面,一般挨着 ‘ ROBOTSTXT_OBEY = True

  配置管道:

1 ITEM_PIPELINES = {
2    'Tencent_recruit.pipelines.TencentRecruitPipeline': 100,
3    'Tencent_recruit.pipelines.DetailRecruitPipeline': 300,
4 }

  管道文件里有两个类,在这里我们将他们两个都配置进来,后边的分值表示优先级,分值

越小越优先。当爬虫文件yield item时,会先传给分值低的,依次传到分值高的。要注意的是每

次返回都会传给这些所有的类!!!

 

posted @ 2018-05-14 15:35  巴蜀秀才  阅读(144)  评论(0编辑  收藏  举报