初识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时,会先传给分值低的,依次传到分值高的。要注意的是每
次返回都会传给这些所有的类!!!