Scrapy之一个item包含多级页面的处理方案
目标
在实际开发过程中,我们所需要的数据往往需要通过多个页面的数据汇总得到,通过列表获取到的数据只有简单的介绍。站在Scrapy框架的角度来看,实际上就是考虑如何处理一个item包含多级页面数据的问题。本文将以获取叶子猪网站的手游排行榜及手游详情为学习案例来解决这个问题。
版本
Scrapy 2.12.0
实战
第一步:搭建Scrapy框架。略过,如果不会搭建的通过可以看我之前的Scrapy入门文章。
第二步:通过打开目标网页,查看网页代码,我们可以的到手游排行榜的基础信息,这里我们只获取标题。
import scrapy
class SytopSpider(scrapy.Spider):
name = "sytop"
allowed_domains = ["sy.yzz.cn"]
start_urls = ["http://sy.yzz.cn/news/14324-1.shtml"]
def parse(self, response):
a_list = response.xpath("//ul[@class='item-pt-list']/li/div[1]/a")
for a in a_list:
# 标题
alt = a.xpath("./img/@alt").get()
print(alt)
第三步:进入二级页面,获取描述信息。此时日志打印可以看到,单个游戏的信息并没有组合起来。
import scrapy
class SytopSpider(scrapy.Spider):
name = "sytop"
allowed_domains = ["sy.yzz.cn"]
start_urls = ["http://sy.yzz.cn/news/14324-1.shtml"]
def parse(self, response):
a_list = response.xpath("//ul[@class='item-pt-list']/li/div[1]/a")
for a in a_list:
# 标题
alt = a.xpath("./img/@alt").get()
print(alt)
# 二级页面的url
info_url = a.xpath("./@href").get()
print(f'二级页面的url是:{info_url}')
meta = {
"alt": alt
}
yield scrapy.Request(url=info_url, callback=self.parse_info)
def parse_info(self, response):
p_list = response.xpath("//div[@class='content']//p")
for p in p_list:
content=p.xpath("string(.)").get()
print(content)
第四步:组合item数据。scrapy.Request方法中的meta参数很重要,它实现了深度爬取。比如:在爬取多层级页面时,使用 meta 参数传递父页面的信息到子页面。
import scrapy
from yezizhu.items import YezizhuItem
class SytopSpider(scrapy.Spider):
name = "sytop"
allowed_domains = ["sy.yzz.cn"]
start_urls = ["http://sy.yzz.cn/news/14324-1.shtml"]
def parse(self, response):
a_list = response.xpath("//ul[@class='item-pt-list']/li/div[1]/a")
for a in a_list:
# 标题
alt = a.xpath("./img/@alt").get()
# 二级页面的url
info_url = a.xpath("./@href").get()
meta = {
"alt": alt
}
yield scrapy.Request(url=info_url, callback=self.parse_info,meta=meta)
def parse_info(self, response):
p_list = response.xpath("//div[@class='content']//p")
print("==============start================")
alt = response.meta["alt"]
print(alt)
content=""
for p in p_list:
content=content+"\n"+p.xpath("string(.)").get()
print(content)
第五步:创建item属性。
class YezizhuItem(scrapy.Item):
alt = scrapy.Field()
content = scrapy.Field()
第六步:传递item属性值,并将item对象传递给管道。
import scrapy
from yezizhu.items import YezizhuItem
class SytopSpider(scrapy.Spider):
name = "sytop"
allowed_domains = ["sy.yzz.cn"]
start_urls = ["http://sy.yzz.cn/news/14324-1.shtml"]
def parse(self, response):
a_list = response.xpath("//ul[@class='item-pt-list']/li/div[1]/a")
for a in a_list:
# 标题
alt = a.xpath("./img/@alt").get()
# 二级页面的url
info_url = a.xpath("./@href").get()
meta = {
"alt": alt
}
yield scrapy.Request(url=info_url, callback=self.parse_info,meta=meta)
def parse_info(self, response):
p_list = response.xpath("//div[@class='content']//p")
print("==============start================")
alt = response.meta["alt"]
print(alt)
content=""
for p in p_list:
content=content+"\n"+p.xpath("string(.)").get()
print(content)
top_content=YezizhuItem(alt=alt, content=content)
yield top_content
第七步:在settings.py文件中开启管道。
ITEM_PIPELINES = {
"yezizhu.pipelines.YezizhuPipeline": 300,
}
第八步:在管道中设置下载数据并启动项目。
import json
class YezizhuPipeline:
# 在爬虫文件开始之前就执行的方法
def open_spider(self, spider):
self.fp = open("C:\\Users\\Administrator\\Desktop\\test\\a.json", "w", encoding="utf-8")
self.fp.write("[")
def process_item(self, item, spider):
line = json.dumps(dict(item), ensure_ascii=False) + ",\n"
self.fp.write(line)
return item
# 在爬虫文件执行之后再执行的方法
def close_spider(self, spider):
# 删除最后一个多余的逗号,并关闭 JSON 数组
self.fp.seek(self.fp.tell() - 3, 0)
self.fp.write("\n]")
self.fp.close()