Scrapy 抓取无限滚动页面
在单页应用以及每页具有大量 AJAX 请求的时代,很多网站已经用花哨的无限滚动机制取代了“前一个/下一个”分页按钮。使用这种技术的网站每当用户滚动到页面的底部的时候加载新项(想想微博,Facebook,谷歌图片)。虽然 UX 专家 认为,无限滚动为用户提供了海量数据,但是我们看到越来越多的 web 页面诉诸于展示这种无休止的结果列表。
在开发 web 爬虫时,我们要做的第一件事就是找到能将我们引导到下一页结果的带有链接的 UI 组件。不幸的是,这些链接在无限滚动页面上不存在。
虽然这种场景可能看起来像诸如 Splash 或者 Selenium 这样的 JavaScript 引擎的一个经典案例,但是它实际上是一个简单的修复。你所需要做的是在你滚动目标页面的时候检查浏览器的 AJAX 请求,然后在 Scrapy spider 中重新创建这些请求,而不是模拟用于与此类引擎的交互。
让我们以 Spidy Quotes 为例,构建一个爬虫来获取上面列出来的所有的项。
审查页面
先说重要的事,我们需要理解无限滚动是如何在这个页面工作的,我们可以通过 浏览器的开发者工具 中的 Network 面板来完成此项工作。打开该面板,然后滚动页面,看看浏览器发送了什么请求:
点开一个请求仔细看看。浏览器发送了一个请求到 /api/quotes?page=x
,然后接收诸如以下的一个 JSON 对象作为响应:
{
"has_next":true,
"page":8,
"quotes":[
{
"author":{
"goodreads_link":"/author/show/1244.Mark_Twain",
"name":"Mark Twain"
},
"tags":["individuality", "majority", "minority", "wisdom"],
"text":"Whenever you find yourself on the side of the ..."
},
{
"author":{
"goodreads_link":"/author/show/1244.Mark_Twain",
"name":"Mark Twain"
},
"tags":["books", "contentment", "friends"],
"text":"Good friends, good books, and a sleepy ..."
}
],
"tag":null,
"top_ten_tags":[["love", 49], ["inspirational", 43], ...]
}
这就是我们的爬虫需要的信息了。它所需要做的仅是生成到"/api/quotes?page=x"的请求,其中, x
的值不断增加,直到 has_next
字段为 false。这样做最棒的是,我们甚至无需爬取 HTML 内容以获取所需数据。这些数据都在一个漂亮的机器可读的 JSON 中。
构建 Spider
下面是我们的 spider。它从服务器返回的 JSON 内容提取目标数据。这种方法比挖掘页面的 HTML 树更容易并且更健壮,相信布局的改变不会搞挂我们的 spider。
import json
import scrapy
class SpidyQuotesSpider(scrapy.Spider):
name = 'spidyquotes'
quotes_base_url = 'http://spidyquotes.herokuapp.com/api/quotes?page=%s'
start_urls = [quotes_base_url % 1]
download_delay = 1.5
def parse(self, response):
data = json.loads(response.body)
for item in data.get('quotes', []):
yield {
'text': item.get('text'),
'author': item.get('author', {}).get('name'),
'tags': item.get('tags'),
}
if data['has_next']:
next_page = data['page'] + 1
yield scrapy.Request(self.quotes_base_url % next_page)
要进一步练习这个技巧,你可以做个实验,爬取我们的博客,因为它也是使用无限滚动来加载旧博文的。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论