Scrapy CrawlSpider + Splash:如何通过链接提取器跟踪链接?



>我有以下代码部分工作,

class ThreadSpider(CrawlSpider):
name = 'thread'
allowed_domains = ['bbs.example.com']
start_urls = ['http://bbs.example.com/diy']
rules = (
Rule(LinkExtractor(
allow=(),
restrict_xpaths=("//a[contains(text(), 'Next Page')]")
),
callback='parse_item',
process_request='start_requests',
follow=True),
)
def start_requests(self):
for url in self.start_urls:
yield SplashRequest(url, self.parse_item, args={'wait': 0.5})
def parse_item(self, response):
# item parser

代码将仅运行start_urls但不会遵循restricted_xpaths中指定的链接,如果我注释掉start_requests()方法和规则中process_request='start_requests',行,它将按预期运行并遵循链接,当然没有 js 渲染。

我已经阅读了两个相关的问题,带有 Splash 的 CrawlSpider 在第一个 URL 后卡住了,CrawlSpider 与 Splash 一起,并在start_requests()方法中专门将scrapy.Request()更改为SplashRequest(),但这似乎不起作用。我的代码有什么问题? 谢谢

我遇到了类似的问题,似乎特定于将Splash与Scrapy CrawlSpider集成。它将仅访问起始 URL,然后关闭。我设法让它工作的唯一方法是不使用 scrapy-splash 插件,而是使用"process_links"方法将 Splash http api url 附加到 scrapy 收集的所有链接。然后我做了其他调整,以弥补这种方法产生的新问题。这是我所做的:

您需要这两个工具来组合启动 url,然后如果您打算将其存储在某个地方,请将其拆开。

from urllib.parse import urlencode, parse_qs

随着每个链接的启动 url 的前缀,scrapy 会将它们全部过滤为"站外域请求",因此我们将"localhost"作为允许的域。

allowed_domains = ['localhost']
start_urls = ['https://www.example.com/']

但是,这带来了一个问题,因为当我们只想抓取一个站点时,我们最终可能会无休止地抓取网络。让我们使用 LinkExtractor 规则来解决这个问题。通过仅从我们想要的域中抓取链接,我们可以解决异地请求问题。

LinkExtractor(allow=r'(http(s)?://)?(.*.)?{}.*'.format(r'example.com')),
process_links='process_links',

这是process_links方法。urlencode 方法中的字典是放置所有启动参数的地方。

def process_links(self, links):
for link in links:
if "http://localhost:8050/render.html?&" not in link.url:
link.url = "http://localhost:8050/render.html?&" + urlencode({'url':link.url,
    'wait':2.0})
return links

最后,若要将 url 从启动 URL 中取出,请使用 parse_qs 方法。

parse_qs(response.url)['url'][0] 

关于这种方法的最后一点说明。您会注意到我在开头的启动 url 中有一个"&"。(...渲染.html?&(。这使得解析启动 url 以取出实际 url 是一致的,无论您在使用 urlencode 方法时具有什么顺序的参数。

似乎与 https://github.com/scrapy-plugins/scrapy-splash/issues/92 有关

我个人使用 dont_process_response=True,所以响应是 HtmlResponse(这是 _request_to_follows 中的代码所必需的(。

我还在我的 spyder 中重新定义了 _build_request 方法,如下所示:

def _build_request(self, rule, link):
r = SplashRequest(url=link.url, callback=self._response_downloaded, args={'wait': 0.5}, dont_process_response=True)
r.meta.update(rule=rule, link_text=link.text)
return r 

在 github 问题中,一些用户只是在他们的类中重新定义了 _request_to_follow 方法。

使用以下代码 - 只需复制和粘贴

restrict_xpaths=('//a[contains(text(), "Next Page")]')

而不是

restrict_xpaths=("//a[contains(text(), 'Next Page')]")

最新更新