爬虫 | 美食数据抓取

发布时间 2023-07-28 11:53:50作者: 张Zong在修行

本实验将为大家介绍接口爬取的相关知识,通过实验楼课程列表页与 IT 之家动态页,讲解如何通过开发者工具快速判断数据来源。实验过程将通过爬取美食网、实验楼社区两个案例,说明如何针对接口编写爬虫。

知识点

  • 接口(API) 爬取知识
  • 美食案例实操
  • 实验楼社区案例实操

接口(API) 爬取知识

互联网上的任意一个网站呈现在你面前,它的数据渲染方式一般分为两种,第一种是服务器同步渲染,第二种是服务器异步渲染,这两种方式之间的差异,了解服务器端应用开发的同学比较清楚,如果你对服务器编程不是很熟悉,也不用担心,虽然在肉眼上观看网页无法直接判断它们的差异,但是通过本实验,你将学会如何快速的区分网页渲染的方式,掌握之后,你的爬虫编写能力可以快速拔高一截。

首先简单的学习上一段落中的两个新概念,同步与异步。

  • 同步,服务器将网页结构与数据一起返回,呈现在你面前的网页是服务器直接打包返回的;
  • 异步,服务器先将网页结构返回,再通过调用接口或者其它方式将数据传输到浏览器,之后替换到网页指定位置,简单理解就是呈现在你面前的网页先呈现的是一个框架,再填的数据。

概念性的内容在初学阶段能建立认知即可,不用钻到细节中去。

判断接口数据返回方式

在爬虫编写的时候,爬虫开发者需要快速的寻找到数据来源,以便编写最优的数据获取代码,如果数据是由服务器打包返回的,那按照以前实验的办法解析网页即可,如果数据是由接口返回的,找到对应的接口,能极大的提高数据获取的速度与精准性,甚至爬虫的运行速度都会大幅的提高。

接下来,我们就学习一下如何快速判断数据来源。

查看网页数据是否出现在网页源码中

通过比对的数据的方式,可以初步判断网页数据是否是服务器直接打包返回的。具体的办法是打开一个待爬取的页面,查看该网页的源码,然后通过搜索功能,在网页源码中寻找目标数据是否存在(目标数据随机选择一个即可)。

例如,打开 实验楼课程 页面,在网页源码中检索 Python 新手入门课,确认是否在源码中出现该内容。

经过搜索,发现源码中确实存在该数据内容,那抓取本页面基本上是不能通过接口去抓取的。为何说是基本不能,因为存在一种场景是第一页的数据是由服务器直接返回的,但是第二页开始却是由接口返回的,这种情况可以参考下述案例。

首页数据由服务器返回,第二页数据由接口返回

打开 IT 之家动态 页面,在该页面的源码中检索页面任意目标元素,例如 大众中国投资入股江淮汽车,持股比例50%

在对应的网页源码中,确实发现了上图红框数据,这时先不要着急下结论,认为该网站爬取不能通过接口爬取。向下滚动页面,结果出现 加载更多 按钮,很多时候当出现类似名称的按钮,你可以大胆的下结论该页面的数据是通过接口返回的,这种情况的出现也反向证明了刚才学习的通过查看源码的方式,并不能 100%确定一个网页是否是由接口数据返回之后在进行渲染的,具体还要依据情况进行判断。

通过开发者工具中的网络请求(Network)进行判断

在编写爬虫代码过程中,对于网页数据获取方式,更多的是依据浏览器开发者工具中的 Network 选项卡进行判断,例如还是 IT 之家动态 这个页面,打开开发者工具中的 Network 选项卡,刷新一下页面。

Network中可以看到刷新页面之后的所有请求记录,如下图所示。

在爬虫编写过程中,以上图片涉及场景使用频率极高,重点注意下图框选区域。

图片内容说明:

  • 数字 1 区域主要控制请求流和筛选请求流,实心红点表示停止获取请求,空心斜杠圆表示清除请求,右侧分别是筛选和查找,最重要的是后面的 Preserve log,该内容适用于当页面刷新或者自动跳转时,将所有的请求日志全部记录下来;
  • 数字 2 区域是筛选区域,主要用于筛选请求内容,例如 All 表示全部,XHR 表示的就是接口数据,JS 表示的是 JS 文件,以此类推;
  • 数字 3 区域就是请求区域了,点击之后就进入请求头和响应头相关内容。

下面核心演示一下如何判断数据的获取方式,勾选 XHR 之后在页面中点击 加载更多 按钮,注意看是否捕获到新的请求。

随着每次点击,都会在 Network 选项卡下出现新的请求数据,如下图所示,可以多点击几次,获取足够多的样板数据。

如果你的目标爬取网站也出现类似效果,你就可以大胆的下结论,数据的来源是异步获取或者叫做通过调用接口返回数据。

点击任意一个连接,切换到右侧的 Preview 选项卡,成功看到 JSON 格式的数据:

如果一个网站数据返回如上图所示,那你应该感到非常高兴,因为在后续的抓取过程中,编码将变的特别简单,而且数据的处理与存储也简化了很多,这种情况就相当于目标网站直接把数据送到你的面前。

美食案例实操

有了识别网站数据来源的能力,我们可以对任何一个网站进行相关分析,这里必须要告诉大家一个爬虫技巧,如果一个网站能找到数据来源接口,那就优先爬取它。

本案例要爬取的网站为 美食天下,拿到目标网站之后,要做的第一步就是使用开发者工具,确定是否有接口在异步传输数据到网页上。

多次点击 加载更多 按钮之后,在 Network 选项卡出现了下述图片相关请求,并且注意到请求地址的最后一个参数不同,page=数字,该参数可以直接确定是目标页码。

编码环节

连接获取到之后,就需要对请求方式,请求参数,响应内容进行分析,点击任意上述连接即可。

分析之后得到的关键点如下:

请求地址为:https://home.meishichina.com/ajax/ajax.php?ac=recipe&op=getMoreDiffStateRecipeList&classid=0&orderby=hot&page=数字
请求方式为:get
响应数据格式为:JSON
格式模板:
{
    data:[],
    error:0
}
# 以上数据 data 是目标数据,error 表示请求状态,测试之后发现 0 表示成功,-2 表示失败

有了上述内容之后,就可以通过之前课程学习的 requests 库加上 JSON 解析模块,进行代码编写了。

将如下代码写入 /home/project/meishi.py 文件:

import requests

def get_data(page):
    headers = {
        "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36"
    }
    # 请求数据
    payload = {'ac': 'recipe',
               'op': 'getMoreDiffStateRecipeList',
               'classid': '0',
               'orderby': 'hot',
               'page': page}
    url = "https://home.meishichina.com/ajax/ajax.php"
    res = requests.get(url, headers=headers, params=payload)
    # 直接以 JSON 格式返回
    print(res.json())

if __name__ == "__main__":
    get_data(2)

核心代码已经完成,通过循环就可以完成任务,这里一个潜在的问题是我们并不知道最终的页码是多少,也就是你无法定义循环的次数。

执行程序结果如下:

在编写爬虫代码的时候,通用的解决方案是手动调整待抓取的连接中页码参数,随意设置一个值,然后逐步调整,直到获取不到数据为止。

例如,请求地址为:

https://home.meishichina.com/ajax/ajax.php?ac=recipe&op=getMoreDiffStateRecipeList&classid=0&orderby=hot&page=50

上述连接已经将 page 设置为 50,依旧获取到了数据,继续放大,当设置为 51 的时候,返回的数据如下,此时表示数据已经获取不到了。

{ "error": -2 }

当然本案例还有一个优点,当没有数据时,直接给了一个 JSON 格式的内容,通过判断 error 这个参数,就可以知道是否存在数据了。

关于 JSON 格式数据解析,属于 Python 基础知识部分,与存储数据相同,本系列实验不做讲解,大家自行完成即可。

实验楼社区案例实操

学习完上文内容之后,很多同学可能会认为如果网页中存在 加载更多 按钮,数据就可以通过接口获取,如果网页是普通的分页,数据就必须通过正则表达式或者之前学习过的各种解析库获取。其实不然,很多时候对于目标网站都需要进行单独分析,分析完毕才可以确定数据的获取方式。

例如,实验楼社区模块,该网页底部具有典型的数字分页标识。

使用开发者工具获取网页相关请求之后发现,网页上的数据依旧是异步加载的,具体的请求如下图所示。

图片中 数字 1 为请求地址,数字 2 为请求返回的数据。多次尝试之后,获取到的地址如下:

https://www.lanqiao.cn/api/v2/questions/?topic_type=newest&sort=answered_time&page=1
https://www.lanqiao.cn/api/v2/questions/?topic_type=newest&sort=answered_time&page=2
https://www.lanqiao.cn/api/v2/questions/?topic_type=newest&sort=answered_time&page=3
...

接下来你可以继续分析请求方式,请求参数,响应内容,继而编写出相应的代码,实验楼社区爬虫案例中一个简单的地方是,由于是数字分页,所以最后的页码是可以直接看到的,也就是上图中的 1727,这个是总页码,所以使用一个循环即可抓取全部社区的数据。

学习过程中,请注意控制每次抓取的时间间隔,一般设置为 2 秒左右即可,不会对目标网站服务器产生任何影响。

实验总结

本实验核心内容就是为大家分析拿到爬取需求之后,如何找到更好的抓取方式,如果网页数据由接口返回,那我们就可以直接面向接口编写爬虫程序,快速完成目标。

通过各种库去爬取数据,属于这一层次,相当于掌握了各种工具,然后拿着工具去蛮干,掌握分析数据来源就属于这一层次了,你可以针对目标网站进行系统分析,寻找完成目标的最优解。希望本实验中讲解的内容对你编写爬虫程序有所启发。