Scrapy框架之请求传参案例 -- 2019-08-08 20:40:13
Posted gqy02
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Scrapy框架之请求传参案例 -- 2019-08-08 20:40:13相关的知识,希望对你有一定的参考价值。
原文: http://106.13.73.98/__/141/
在某些情况下,我们爬取的数据不在同一个页面。
例如下面的案例1,我们要爬取一个电影网站,电影的排名、名称、主演分在一页,而其它的信息分在二级子页面中。这时,我们就需要用到请求传参。
案例1:爬取97电影网中所有热门电影的详细信息
97电影网热门电影URL:http://www.55xia.com/movie/hotest/
第一步,爬虫文件:
# -*- coding: utf-8 -*- import scrapy from Test.items import TestItem # 请求传参 class Test01Spider(scrapy.Spider): name = 'test01' start_urls = ['http://www.55xia.com/movie/hotest/'] # 97电影网热门电影 def parse(self, response): # 获取所有电影的div div_list = response.xpath('//div[@class="container-fluid"]/div[@class="media"]') for div in div_list: # 准备item对象 item = TestItem() item['ranking'] = div.xpath('.//a[2]/text()').extract_first().strip() # 排行 item['title'] = div.xpath('.//div[@class="media-body"]/div[2]/dl/dt/h4//text()').extract_first().strip() # 名称 starring_list = div.xpath('.//div[@class="media-body"]/div[2]/dl/dd/ul/li[2]//text()') # 主演列表 # 格式转换 for index, starring in enumerate(starring_list): starring_list[index] = starring.extract().strip() item['starring'] = ' '.join(starring_list) # 所有主演 # 获取电影详情的url detail_page = div.xpath('.//div[@class="media-body"]/div[2]/dl/dt/h4/a/@href').extract_first() # 有的电影没有详情页面,没有的则不再获取其详情 if detail_page: # 开始拼接电影详情页面的url detail_url = 'http://www.55xia.com' + detail_page # 手动发起请求 yield scrapy.Request(url=detail_url, callback=self.get_detail_page, meta='item': item) # ?? # callback:指定回调函数,即解析的方法 # meta='item': item:实现请求传参,?? # 没有详情页面的直接提交给管道 else: yield item # 递归获取所有页面的内容 page_url = 'http://www.55xia.com/movie/hotest?page=%d' for i in range(2, 6): url = format(page_url % i) yield scrapy.Request(url=url, callback=self.parse) # 自己定义的解析方法,用于解析新页面中电影的详情 def get_detail_page(self, response): item = response.meta['item'] item['director'] = > response.xpath('/html/body/div[1]/div/div/div[1]/div[1]/div[2]/table/tbody/tr[1]/td[2]/a/text()').extract_first() # 导演 item['writers'] = response.xpath('/html/body/div[1]/div/div/div[1]/div[1]/div[2]/table/tbody/tr[2]/td[2]/a/text()').extract_first() # 编剧 item['type'] = response.xpath('/html/body/div[1]/div/div/div[1]/div[1]/div[2]/table/tbody/tr[3]/td[2]/a/text()').extract_first() # 类型 item['region'] = response.xpath('/html/body/div[1]/div/div/div[1]/div[1]/div[2]/table/tbody/tr[4]/td[2]/a/text()').extract_first() # 地区 item['language'] = response.xpath('/html/body/div[1]/div/div/div[1]/div[1]/div[2]/table/tbody/tr[5]/td[2]/text()').extract_first() # 语言 item['release_time'] = response.xpath('/html/body/div[1]/div/div/div[1]/div[1]/div[2]/table/tbody/tr[6]/td[2]/text()').extract_first() # 上映时间 # 提交给管道 yield item
第二步,数据结构模板文件:
import scrapy class TestItem(scrapy.Item): # define the fields for your item here like: ranking = scrapy.Field() # 排行 title = scrapy.Field() # 名称 starring = scrapy.Field() # 主演 director = scrapy.Field() # 导演 writers = scrapy.Field() # 编剧 type = scrapy.Field() # 类型 region = scrapy.Field() # 地区 language = scrapy.Field() # 语言 release_time = scrapy.Field() # 上映时间
第三步,管道文件:
import json class TestPipeline(object): # fp = None # 用于文件操作符 # 重写父类方法,用于打开文件 def open_spider(self, spider): """此方法在运行爬虫文件时自动执行,注意:只会执行一次""" self.fp = open('./text.txt', 'w', encoding='utf-8') def process_item(self, item, spider): # 开始写入文件 self.fp.write(json.dumps(item.__dict__['_values'], ensure_ascii=False) + '\n') # ensure_ascii=False 这样可使数据显示的为中文 return item # 如果你还有其它的(优先级低的)管道类,那么你一定要返回item # 重写父类方法,用于关闭文件 def close_spider(self, spider): """此方法在结束爬虫文件时自动执行,注意:只会执行一次""" self.fp.flush() self.fp.close()
第四步,配置文件:
# 开启管道类 ITEM_PIPELINES = 'Test.pipelines.TestPipeline': 300,
展示效果图:
案例2:爬取彼岸图网的所有图片
第一步,爬虫文件:
# -*- coding: utf-8 -*- import scrapy from Test.items import TestItem class Test01Spider(scrapy.Spider): name = 'test01' start_urls = ['http://pic.netbian.com/'] # 彼岸图网 max_page = 100 # 你想要下载多少页图片 present_page = 2 # 用于标识当前所在的页面 url = 'http://pic.netbian.com/index_%d.html' # 用于定位页面的url def parse(self, response): # 获取每张图片所在的li li_list = response.xpath('//ul[@class="clearfix"]/li') # 开始解析数据: for li in li_list: img_src = li.xpath('.//a//img/@src').extract_first() # type: str # 获取所有每张图片的路径 item = TestItem() item['name'] = img_src.split('/')[-1] # 保存图片名称 img_url = self.start_urls[0] + img_src # 每张图片的链接 # 手动向每张图片链接发起请求 yield scrapy.Request(img_url, callback=self.get_img, meta='item': item) # ! # callback:指定回调函数,即解析的方法 # meta='item': item:请求传参 # 递归解析所有页面数据 if self.present_page <= self.max_page: url = format(self.url % self.present_page) yield scrapy.Request(url, callback=self.parse) self.present_page += 1 def get_img(self, response): item = response.meta['item'] # 提取传过来的参数 item['img_data'] = response.body # 获取图片bytes数据 yield item # 提交给管道
第二步,数据结构模板文件:
import scrapy class TestItem(scrapy.Item): # define the fields for your item here like: name = scrapy.Field() # 图片名称 img_data = scrapy.Field() # 图片bytes数据
第三步,管道文件:
import os class TestPipeline(object): def open_spider(self, spider): # 定义好用于保存文件的路径 self.dirname = r'C:\Users\zyg\Desktop\彼岸花\\' # 如果不存在此文件夹,则创建 if not os.path.exists(self.dirname): os.mkdir(self.dirname) def process_item(self, item, spider): img_path = self.dirname + item['name'] with open(img_path, 'wb') as fp: fp.write(item['img_data']) return item
第四步,配置文件:
# 开启管道类 ITEM_PIPELINES = 'Test.pipelines.TestPipeline': 300, # 下载量较大,所以我们这里将开启的线程数加大 CONCURRENT_REQUESTS = 200
展示效果图:
原文: http://106.13.73.98/__/141/
以上是关于Scrapy框架之请求传参案例 -- 2019-08-08 20:40:13的主要内容,如果未能解决你的问题,请参考以下文章
python爬虫---scrapy框架爬取图片,scrapy手动发送请求,发送post请求,提升爬取效率,请求传参(meta),五大核心组件,中间件