使用Scrapy,我试图从维基百科中搜索所有语言的链接网络。每个维基百科页面都应包含指向维基数据项目的链接,该项目可以唯一标识所有语言的页面主题。我试图实现的过程如下:
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中处理分页,而不是如何处理以这种方式“折叠”一个链接。
答案 0 :(得分:1)
只要蜘蛛没有问题,你真正想要的就是当你运行
时make install
它应该yield Request(url=urljoin(response.url, str(target)), \
callback=self.parse_wikidata, \
meta={"item": item})
早于下面类型的排队请求
yield
如果查看文档
https://doc.scrapy.org/en/latest/topics/request-response.html
priority(int) - 此请求的优先级(默认为0)。调度程序使用优先级来定义用于处理请求的顺序。具有更高优先级值的请求将更早执行。允许使用负值以指示相对较低的优先级。
所以你将使用
yield Request(url=urljoin(response.url, str(s)), \
callback=self.parse, meta={"item": item})
和
yield Request(url=urljoin(response.url, str(target)), \
callback=self.parse_wikidata, \
meta={"item": item}, priority=1)
这将确保刮刀优先考虑将导致数据首先被删除的链接