在Scrapy中递归折叠二级链接
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在Scrapy中递归折叠二级链接相关的知识,希望对你有一定的参考价值。
使用Scrapy,我试图从所有语言中删除维基百科的链接网络。每个维基百科页面都应包含指向维基数据项目的链接,该项目可以唯一标识所有语言的页面主题。我试图实现的过程如下所示:
- 首先,从每个页面(“源”链接)中提取维基数据链接。
- 迭代页面上的其余链接。
- 对于每个链接,使用新的回调函数向相应的页面(“目标”链接)发送请求。
- 从相应的目标页面中提取Wikidata链接。
- 迭代目标页面上的所有链接并回调原始的
parse
函数。
基本上,我想跳过给定源页面上的中间链接,而是抓住相应的维基数据链接。
这是我到目前为止的(半工作)代码:
from urllib.parse import urljoin, urlparse
from scrapy import Spider
from wiki_network.items import WikiNetworkItem
WD =
"//a/@href[contains(., 'wikidata.org/wiki/Special:EntityPage')
and not(contains(., '#'))][1]"
TARGETS =
"//a/@href[contains(., '/wiki/')
and not(contains(., 'wikidata'))
and not(contains(., 'wikimedia'))]"
class WikiNetworkSpider(Spider):
name = "wiki_network"
allowed_domains = ["wikipedia.org"]
start_urls = ["https://gl.wikipedia.org/wiki/Jacques_Derrida"]
filter = re.compile(r"^.*(?!.*:[^_]).*wiki.*")
def parse(self, response):
# Extract the Wikidata link from the "source" page
source = response.xpath(WD).extract_first()
# Extract the set of links from the "source" page
targets = response.xpath(TARGETS).extract()
if source:
source_title = response.xpath("//h1/text()").extract_first()
for target in targets:
if self.filter.match(str(target)) is not None:
item = WikiNetworkItem()
item["source"] = source
item["source_domain"] = urlparse(response.url).netloc
item["refer"] = response.url
item["source_title"] = source_title
# Yield a request to the target page
yield Request(url=urljoin(response.url, str(target)),
callback=self.parse_wikidata,
meta={"item": item})
def parse_wikidata(self, response):
item = WikiNetworkItem(response.meta["item"])
wikidata_target = response.xpath(WD).extract_first()
if wikidata_target:
# Return current item
yield self.item_helper(item, wikidata_target, response)
# Harvest next set of links
for s in response.xpath(TARGETS).extract():
if self.filter.match(str(s)) is not None:
yield Request(url=urljoin(response.url, str(s)),
callback=self.parse, meta={"item": item})
def item_helper(self, item, wikidata, response):
print()
print("Target: ", wikidata)
print()
if item["source"] != wikidata:
target_title = response.xpath("//h1/text()").extract_first()
item["target"] = wikidata
item["target_title"] = target_title
item["target_domain"] = urlparse(response.url).netloc
item["target_wiki"] = response.url
print()
print("Target: ", target_title)
print()
return item
蜘蛛运行并刮擦链接一段时间(刮取的项目数通常达到620左右),但最终它会建立一个庞大的队列,完全停止刮擦,然后继续爬行。我是否应该期待它在某个时刻再次开始刮擦?
似乎应该有一种简单的方法在Scrapy中进行这种二级抓取,但到目前为止我读过的其他问题似乎主要是关于如何在Scrapy中处理分页,而不是如何“折叠” “以这种方式的链接。
答案
只要蜘蛛没有问题,你真正想要的就是当你跑步时
yield Request(url=urljoin(response.url, str(target)),
callback=self.parse_wikidata,
meta={"item": item})
它应该yield
早于下面类型的排队请求
yield Request(url=urljoin(response.url, str(s)),
callback=self.parse, meta={"item": item})
如果你看一下文档
https://doc.scrapy.org/en/latest/topics/request-response.html
priority(int) - 此请求的优先级(默认为0)。调度程序使用优先级来定义用于处理请求的顺序。具有更高优先级值的请求将更早执行。允许使用负值以指示相对较低的优先级。
所以你会用
yield Request(url=urljoin(response.url, str(target)),
callback=self.parse_wikidata,
meta={"item": item}, priority=1)
和
yield Request(url=urljoin(response.url, str(s)),
callback=self.parse, meta={"item": item}, priority=-1)
这将确保刮刀优先考虑将导致数据首先被刮除的链接
以上是关于在Scrapy中递归折叠二级链接的主要内容,如果未能解决你的问题,请参考以下文章