在抓取时,您可能会遇到动态网页,其中页面的某些部分是通过多个请求动态加载的。虽然这可能非常棘手,但Developer Tools中的Network -tool极大地促进了这项任务。为了演示Network-tool,我们来看一下quotes.toscrape.com/scroll页面。
该页面与基本的quotes.toscrape.com -page 非常相似,但是Next当您滚动到底部时,页面会自动加载新的引号,而不是上面提到的按钮。我们可以直接尝试不同的XPath,但是我们将从scrapy shell中检查另一个非常有用的命令:
$ scrapy shell "quotes.toscrape.com/scroll"
(...)
>>> view(response)
浏览器窗口应该与网页一起打开,但有一个重要的区别:我们只看到带有单词的绿色栏,而不是引号Loading...。
该view(response)命令让我们查看我们的shell或稍后我们的蜘蛛从服务器收到的响应。在这里,我们看到加载了一些基本模板,其中包括标题,登录按钮和页脚,但缺少引号。这告诉我们引号是从不同的请求加载的quotes.toscrape/scroll。
如果单击Network选项卡,则可能只会看到两个条目。我们要做的第一件事是通过点击启用持久性日志。如果禁用此选项,则每次导航到其他页面时都会自动清除日志。启用此选项是一个很好的默认选项,因为它使我们可以控制何时清除日志。Persist Logs
如果我们现在重新加载页面,您将看到日志中填充了六个新请求。
在这里,我们看到重新加载页面时所做的每个请求,并且可以检查每个请求及其响应。那么让我们来看看我们的报价来自哪里:
首先单击名称请求scroll。在右侧,您现在可以检查请求。在Headers你会发现关于请求头,如URL,该方法中,IP地址等详细信息。我们将忽略其他标签并直接点击Reponse。
您应该在Preview窗格中看到的是呈现的HTML代码,这正是我们view(response)在shell中调用时看到的内容。因此,type日志中的请求是html。其他请求的类型有css或者js,但我们感兴趣的是quotes?page=1使用该类型调用的一个请求json。
如果我们单击此请求,我们会看到请求URL是 http://quotes.toscrape.com/api/quotes?page=1,并且响应是包含我们的引号的JSON对象。我们还可以右键单击请求并打开以获得更好的概述。Open in new tab
通过此响应,我们现在可以轻松地解析JSON对象,并请求每个页面获取网站上的每个引用:
import scrapy
import json
class QuoteSpider(scrapy.Spider):
name = 'quote'
allowed_domains = ['quotes.toscrape.com']
page = 1
start_urls = ['http://quotes.toscrape.com/api/quotes?page=1]
def parse(self, response):
data = json.loads(response.text)
for quote in data["quotes"]:
yield {"quote": quote["text"]}
if data["has_next"]:
self.page += 1
url = "http://quotes.toscrape.com/api/quotes?page={}".format(self.page)
yield scrapy.Request(url=url, callback=self.parse)
这个蜘蛛从quotes-API的第一页开始。对于每个响应,我们解析response.text并分配给它data。这使我们可以在Python字典上操作JSON对象。我们遍历quotes并打印出来quote["text"]。如果方便的has_next元素是true(尝试在浏览器中加载 quotes.toscrape.com/api/quotes?page=10或页码大于10),我们会增加page属性和yield新请求,将增加的页码插入我们的url。
您可以看到,通过Network -tool中的一些检查,我们能够轻松复制页面滚动功能的动态请求。爬行动态页面可能非常令人生畏,页面可能非常复杂,但它(大部分)归结为识别正确的请求并在您的蜘蛛中复制它。