Python网络爬虫(scrapy的日志等级和请求传参)
一、Scrapy的日志等级
在使用scrapy crawl spiderFileName运行程序时,在终端里打印输出的就是scrapy的日志信息。
日志信息的种类:
ERROR : 一般错误
WARNING : 警告
INFO : 一般的信息
DEBUG : 调试信息
设置日志信息指定输出:
# 在settings.py配置文件中,加入 LOG_LEVEL = ‘指定日志信息种类’即可。 LOG_FILE = 'log.txt'则表示将日志信息写入到指定文件中进行存储。 # 例如: LOG_LEVEL = "ERROR" LOG_FILE = 'log.txt'
二、如何提高scrapy的爬取效率(settings配置)
- 增加并发:
默认scrapy开启的并发线程为32个,可以适当进行增加。在settings配置文件中修改CONCURRENT_REQUESTS = 100值为100,并发设置成了为100。
- 降低日志级别:
在运行scrapy时,会有大量日志信息的输出,为了减少CPU的使用率。可以设置log输出信息为INFO或者ERROR即可。在配置文件中编写:LOG_LEVEL = ‘INFO’
- 禁止cookie:
如果不是真的需要cookie,则在scrapy爬取数据时可以进制cookie从而减少CPU的使用率,提升爬取效率。在配置文件中编写:COOKIES_ENABLED = False
- 禁止重试:
对失败的HTTP进行重新请求(重试)会减慢爬取速度,因此可以禁止重试。在配置文件中编写:RETRY_ENABLED = False
- 减少下载超时:
如果对一个非常慢的链接进行爬取,减少下载超时可以能让卡住的链接快速被放弃,从而提升效率。在配置文件中进行编写:DOWNLOAD_TIMEOUT = 10 超时时间为10s
配置文件,settings.py
配置文件: USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36' # Obey robots.txt rules ROBOTSTXT_OBEY = False # 不遵守爬虫文件协议 # Configure maximum concurrent requests performed by Scrapy (default: 16) CONCURRENT_REQUESTS = 100 # 并发线程设置100个 COOKIES_ENABLED = False # 不使用cookie LOG_LEVEL = 'ERROR' # 日志等级输出级别:错误(ERROR)级别才输出到终端 RETRY_ENABLED = False # 网页数据请求失败则不重新请求 DOWNLOAD_TIMEOUT = 3 # 网络请求超时时间3秒 # Configure a delay for requests for the same website (default: 0) # See https://doc.scrapy.org/en/latest/topics/settings.html#download-delay # See also autothrottle settings and docs # The download delay setting will honor only one of: #CONCURRENT_REQUESTS_PER_DOMAIN = 16 #CONCURRENT_REQUESTS_PER_IP = 16 DOWNLOAD_DELAY = 3
三、scrapy手动请求发送与请求传参
案例展示:爬取boos直聘,将boss直聘中的岗位信息,薪资及工作的具体内容进行爬取
3.1 手动请求发送:
在某些情况下,我们爬取内容存在多页数据时,需要自动指定爬取页数,通过递归调用parse函数对每页数据做数据解析
# -*- coding: utf-8 -*- import scrapy from ..items import BoosproItem # 处理手动请求 class BoosSpider(scrapy.Spider): name = 'boos' # allowed_domains = ['www.xx.com'] # 爬虫开始请求的url列表 start_urls = [ 'https://www.zhipin.com/job_detail/?query=python开发&city=101010100&industry=&position='] # 数据解析 def parse(self, response): li_list = response.xpath('//*[@id="main"]/div/div[3]/ul/li | //*[@id="main"]/div/div[2]/ul/li') for li in li_list: job_title = li.xpath('.//div[@class="info-primary"]/h3/a/div[1]/text()').extract_first() salary = li.xpath('.//div[@class="info-primary"]/h3/a/span/text()').extract_first() # 实例化item对象 item = BoosproItem() item["job_title"] = job_title item["salary"] = salary # 提交item对象到管道 yield item # 当添加不满足时,递归结束 if self.page <= 5: self.page += 1 print("正在爬去第{}页数据!".format(self.page)) # 通过url模板拼接新的url new_url = format(self.base_url%self.page) # 手动请求发送 递归调用parse函数,对数据做解析 yield scrapy.Request(new_url, callback=self.parse)
3.1 请求传参:
我们爬取内容职位工作具体内容在每个公司详情页里面,这时候就需要用到动态传参,把item对象传递到详情页的数据解析函数中
参数传递:meta = {"item": item},通过meta关键字传递给callback函数
参数接收:item = response.meta['key']
# -*- coding: utf-8 -*- import scrapy from ..items import BoosproItem # 处理手动请求 # 请求参数处理 class BoosSpider(scrapy.Spider): name = 'boos' # allowed_domains = ['www.xx.com'] # 爬虫开始请求的url列表 start_urls = [ 'https://www.zhipin.com/job_detail/?query=python开发&city=101010100&industry=&position='] # 指定第二页page page = 2 # 指定通用url模板 base_url = "https://www.zhipin.com/c101010100/?query=python开发&page=%d" # 数据解析 def parse(self, response): li_list = response.xpath('//*[@id="main"]/div/div[3]/ul/li | //*[@id="main"]/div/div[2]/ul/li') for li in li_list: job_title = li.xpath('.//div[@class="info-primary"]/h3/a/div[1]/text()').extract_first() salary = li.xpath('.//div[@class="info-primary"]/h3/a/span/text()').extract_first() detail_url = "https://www.zhipin.com"+li.xpath('.//div[@class="info-primary"]/h3/a/@href').extract_first() # 实例化item对象 item = BoosproItem() item["job_title"] = job_title item["salary"] = salary # 职位详情页 请求参数处理(item对象传参) yield scrapy.Request(detail_url, callback=self.detail_parse, meta={"item": item}) # 当添加不满足时,递归结束 if self.page <= 5: self.page += 1 print("正在爬去第{}页数据!".format(self.page)) # 通过url模板拼接新的url new_url = format(self.base_url%self.page) # 递归调用parse函数,对数据做解析 yield scrapy.Request(new_url, callback=self.parse) # 详情页数据解析 回调函数 def detail_parse(self, response): # 获取到item对象 item = response.meta["item"] # 职位描述信息 复数(extract) job_desc = response.xpath('//*[@id="main"]/div[3]/div/div[2]/div[2]/div[1]/div//text()').extract() job_desc = "".join(job_desc) # 对象属性赋值 item["job_desc"] = job_desc # 提交item对象到Pipeline yield item