- 问题:爬虫文件的代码中,我们从来没有手动的对start_urls列表中存储的起始url进行过请求的发送,但是起始url的确是进行了请求的发送,那这是如何实现的呢?
- 解答:其实是因为爬虫文件中的爬虫类继承到了Spider父类中的start_requests(self)这个方法,该方法就可以对start_urls列表中的url发起请求:
def start_requests(self): for u in self.start_urls: yield scrapy.Request(url=u,callback=self.parse)
【注意】该方法默认的实现,是对起始的url发起get请求,如果想发起post请求,则需要子类重写该方法。
-方法: 重写start_requests方法,让其发起post请求:
def start_requests(self): #请求的url post_url = ‘http://fanyi.baidu.com/sug‘ # post请求参数 formdata = { ‘kw‘: ‘wolf‘, } # 发送post请求 yield scrapy.FormRequest(url=post_url, formdata=formdata, callback=self.parse)
在scrapy框架中默认情况下cookie会被自动处理,无需手动!
在使用scrapy crawl spiderFileName运行程序时,在终端里打印输出的就是scrapy的日志信息。
- 日志信息的种类:
ERROR : 一般错误
WARNING : 警告
INFO : 一般的信息
DEBUG : 调试信息
- 设置日志信息指定输出:
在settings.py配置文件中,加入
LOG_LEVEL = ‘指定日志信息种类’ 即可。
LOG_FILE = ‘log.txt‘ 则表示将日志信息写入到指定文件中进行存储。
在某些情况下,我们爬取的数据不在同一个页面中,例如,我们爬取一个电影网站,电影的名称,评分在一级页面,而要爬取的其他电影详情在其二级子页面中。这时我们就需要用到请求传参。
- 案例:爬取boos直聘上的招聘信息,将一级页面中的工作名称,薪资,公司, 二级页面中的工作详情进行爬取。
爬虫文件:
import scrapy from ..items import BoosproItem # 当我们请求的数据不在同一页面中,那么必须使用请求传参 class BoosSpider(scrapy.Spider): name = ‘boos‘ # allowed_domains = [‘www.xxx.com‘] start_urls = [‘https://www.zhipin.com/c101010100/?query=python%E7%88%AC%E8%99%AB&page=1‘] # 通用的url模板 url = ‘https://www.zhipin.com/c101010100/?query=python%E7%88%AC%E8%99%AB&page={}‘ pageNum = 1 def parse(self, response): li_list = response.xpath(‘//div[@class="job-list"]/ul/li‘) for li in li_list: item = BoosproItem() job_name = li.xpath(‘.//div[@class="job-title"]/text()‘).extract_first() salary = li.xpath(‘.//div[@class="info-primary"]/h3/a/span/text()‘).extract_first() company = li.xpath(‘.//div[@class="company-text"]/h3/a/text()‘).extract_first() # url拼接 detail_url = ‘https://www.zhipin.com‘ + li.xpath(‘.//div[@class="info-primary"]/h3/a/@href‘).extract_first() # 将解析到的数据存储到item类型的对象中 item[‘job_name‘] = job_name item[‘salary‘] = salary item[‘company‘] = company # 对详情页的url进行手动请求的发送 , callback请求成功后的回调函数, # 请求传参,将meta所对应的值传递给回调函数 yield scrapy.Request(url=detail_url, callback=self.parsrDetail, meta={‘item‘: item}) # 对其他的页码进行手动请求 if self.pageNum <= 3: self.pageNum += 1 newUrl = self.url.format(self.pageNum) yield scrapy.Request(url=newUrl, callback=self.parse) # 用来解析详情页的相关的数据 def parsrDetail(self,response): # 接收meta item = response.meta[‘item‘] job_desc = response.xpath(‘//*[@id="main"]/div[3]/div/div[2]/div[2]/div[1]/div//text()‘).extract() job_desc = ‘‘.join(job_desc) # 将job_desc封装到item中 item[‘job_desc‘] = job_desc # 提交item 到管道 yield item
items文件:
import scrapy class BoosproItem(scrapy.Item): # define the fields for your item here like: # name = scrapy.Field() job_name = scrapy.Field() salary = scrapy.Field() company = scrapy.Field() job_desc = scrapy.Field()
管道文件:
class BoosproPipeline(object): # 该方法只会被执行一次, def open_spider(self, spider): self.fp = open(‘./boos.txt‘, ‘w‘, encoding=‘utf-8‘) # 用于处理item的方法,爬虫文件每次提交一次item方法就会被调用一次 def process_item(self, item, spider): # 取出item中的值 job_name = item["job_name"].strip() salary = item["salary"].strip() company = item["company"].strip() job_desc = item["job_desc"].strip() self.fp.write(job_name + ":" + salary + "\n" + company + "\n" + job_desc + ‘\n\n‘) return item # 返回给了下一个即将被执行的管道类 # 关闭文件夹 def close_spider(self, spider): self.fp.close()
注意settings中的配置:
开启管道,
robotstxt改为False,
UA伪装,
日志指定输出, LOG_LEVEL = ‘ERROR‘
scrapy框架post请求发送,五大核心组件,日志等级,请求传参
原文:https://www.cnblogs.com/zwq-/p/10591207.html