爬虫请求响应以及提取数据

爬虫请求响应以及提取数据

回顾:
网页给客户端响应数据, 有哪些写法(在爬虫入门之爬虫原理以及请求响应这篇博客咯嘛有提到)?
1.响应对象.text(获取网页数据的时候会用到)
2.响应对象.content(将图片, 音频或视频等数据存放到文件的时候会用到)

那这一篇文章, 介绍一个新的写法:
响应对象.json(), 这个方法在获取网页数据所对应的请求数据时会用到
什么情况下会使用
当再浏览器对应的响应中看到的数据结构有点像python中的字典或者列表(因为浏览器中不叫字典或者列
表,只是说数据格式类似)

我们通过代码的案例, 来讲解响应对象.json()的写法。

代码:

python 复制代码
import requests
url = 'https://careers.tencent.com/tencentcareer/api/post/Query?
timestamp=1726832959000&countryId=&cityId=&bgIds=&productId=&categoryId=&parentCategoryId=&
attrId=1&keyword=&pageIndex=1&pageSize=10&language=zh-cn&area=cn'
res = requests.get(url)
# print(type(res.text)) # 如果使用响应对象.text 那么得到的数据永远都是字符串类型
# print(type(res.json()))# 如果使用响应对象.text 那么得到的数据都是字典类型
data = res.json() # 使用data变量存储字典数据 字典更方便取值
# 结合循环编写解析的代码
count = 1 # 输出的序号
for i in data['Data']['Posts']:
    # 岗位名称
    RecruitPostName = i['RecruitPostName']
    # 所在城市
    LocationName = i['LocationName']
    # 岗位内容
    Responsibility = i['Responsibility']
    print(count,RecruitPostName,LocationName,Responsibility)
    count += 1

这个url怎么来的, 首先打开腾讯招聘

接着点击技术类那个框, 跳转到如下页面:

然后再请求中找到Query……, 这个就是我们需要爬取的数据请求。
每个网站, 需要爬取的数据请求都不一样, 这个需要自己找。
我们双击那个请求, 可以发现, 后台返回了数据。

所以url就是https://careers.tencent.com/tencentcareer/api/post/Query?
timestamp=1726832959000&countryId=&cityId=&bgIds=&productId=&categoryId=&parentCategoryId=&
attrId=1&keyword=&pageIndex=1&pageSize=10&language=zh-cn&area=cn, 也就是请求。

说明:
data = res.json()这句话, 使用data变量存储字典数据, 因为字典更方便取值
我们可以发现请求里面, 有个Posts的列表(数组), 所以我们先要获取到那个列表再循环, 使用for i in data['Data']['Posts']这句话进行循环, 因为Posts列表再Data里面, 所以要data['Data']['Posts']这样写。然后在循环里面, 有三行代码, 获取岗位名称, RecruitPostName = i['RecruitPostName'], 获取所在城市, LocationName = i['LocationName'], 获取岗位内容, Responsibility = i['Responsibility']。因为岗位名称、所在城市、岗位内容这三个东西都在Posts列表里面, 而i就是每一次遍历出来的列表里面的一条数据, 所以可以用i['字段名']这么写。

伪装

python 复制代码
url = 'https://movie.douban.com/j/chart/top_list?
type=10&interval_id=100%3A90&action=&start=0&limit=20'
# 响应的数据格式:[{},{}] 列表嵌套字典
res = requests.get(url)
data = res.json()
print(data) # 报错
# 得到的响应数据不是一个纯列表或者纯字典的时候 就会报如下错误
# requests.exceptions.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
# 改响应对象.text输出
print(res.text) # 当前获取到的数据是空字符串 为什么浏览器可以正常得到数据,而爬虫得不到

结果:

为什么会报错?
原因: 对方识别了当前的客户端是爬虫, 所以不给数据
如何解决: 我们需要用到伪装
如何实现伪装: 在请求头当中带上请求头(从浏览器复制过来)

修改过后的代码:

python 复制代码
# 使用字典保存请求头信息
url = 'https://movie.douban.com/j/chart/top_list?
type=10&interval_id=100%3A90&action=&start=0&limit=20'
# 响应的数据格式:[{},{}] 列表嵌套字典
headers = {
    'user-agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like
    Gecko) Chrome/128.0.0.0 Safari/537.36'
}
# 携带请求头的方式:headers参数传参
res = requests.get(url,headers=headers)
data = res.json()
print(data)
print(text)

此时此刻, 我们就能够获取到数据啦!

我们看一个完整的一个案例, 爬取豆瓣电影的数据:

python 复制代码
import requests

url = 'https://movie.douban.com/j/chart/top_list?type=10&interval_id=100%3A90&action=&start=0&limit=20'
# user-agent对应的是客户端的版本信息Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36
headers = {
    "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36"
}
response = requests.get(url, headers=headers)
# print(response.text)
# print(type(response.json()))
data = response.json()
count = 1
for i in data:
    # i = 第一次循环取出的是 列表种的第一个字典 对应的是一个电影信息
    # 电影名
    title = i['title']
    # 演员表
    actors = i['actors']
    # 评分
    score = i['score']
    # 上映时间
    release_date = i['release_date']
    print(count, "电影标题:", title, ", 演员列表:", actors, ", 评分", score, ", 上映时间", release_date)
    count += 1

运行结果:


由于控制台的数据太多, 无法完全展示。
我们可以看到有电影名, 演员列表, 电影的评分以及电影的上映时间。

基于分页的爬虫

分页爬虫, 是非常常用的爬虫手段, 因为非常多的网站, 它不只是只有当前的一页数据, 它可以有n页的数据, 而我们却不知道这个网站有多少页数据的时候(因为网站会更新, 页数会变化), 我们就可以用分页查询法。

我们还是爬取豆瓣电影的网站
在写代码之前, 我们需要研究一下url, 也就是请求。
https://movie.douban.com/j/chart/top_list?type=10&interval_id=100%3A90&action=&start=0&limit=20
这个代表从第一条数据开始, 查询20条数据
start = 0代表从第一条数据开始, limit = 20代表查询20条数据
https://movie.douban.com/j/chart/top_list?type=10&interval_id=100%3A90&action=&start=20&limit=20
https://movie.douban.com/j/chart/top_list?type=10&interval_id=100%3A90&action=&start=40&limit=20
https://movie.douban.com/j/chart/top_list?type=10&interval_id=100%3A90&action=&start=60&limit=20
https://movie.douban.com/j/chart/top_list?type=10&interval_id=100%3A90&action=&start=80&limit=20
……
通过观察, 我们可以发现只有start参数会变
那如何实现0 20 40 60 80这样多个url呢?
我们需要用到循环
可以用一个变量代表start的值
然后每一次循环, 变量值+20

代码:

python 复制代码
import requests

# 如果循环次数不确定, 就应该写死循环
# 定义页码变量(就是url里面的start)
page = 0
count = 1
# 因为我们不知道什么时候数据才能爬完, 也就是说我们不知道什么时候结束, 所以我们这里会用死循环, 之后根据观察当没有数据的时候, 控制台会返回什么信息, 再做决定如何跳出循环。
while True:
    # url会变, 用刚才定义好的page参数代表url里面的start
    url = f'https://movie.douban.com/j/chart/top_list?type=10&interval_id=100%3A90&action=&start={page}&limit=20'
    # 请求头
    headers = {
        "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36"
    }
    response = requests.get(url, headers=headers)
    data = response.json()
    for i in data:
        # i = 第一次循环取出的是 列表种的第一个字典 对应的是一个电影信息
        # 电影名
        title = i['title']
        # 演员表
        actors = i['actors']
        # 评分
        score = i['score']
        # 上映时间
        release_date = i['release_date']
        print(count, "电影标题:", title, ", 演员列表:", actors, ", 评分", score, ", 上映时间", release_date)
        print(f"第{count}页数据已经全部提取完毕")
        count += 1
    page += 20
    # 无限循环什么时候结束? 数据没有了就应该结束
    if len(data) == 0:
        print(f"第{count}页数据已经全部提取完毕")
        break

结果:

这里要说明一下, if len(data) == 0这句话是判断响应的数据, 是否是空列表, 也就是说判断数据是否已经爬完了。当然, 每个网站, 判断是否结束爬虫的判断方法, 都是不同的, 这个得看实际情况来判断。

这里我们为什么要用if len(data) == 0这样的判断, 我们再把刚才的代码运行一遍的同时再注释小判断结束的语句, 再加上一个print(data)语句, 我们看一看结果会如何。

代码:

python 复制代码
import requests

# 如果循环次数不确定, 就应该写死循环
# 定义页码变量(就是url里面的start)
page = 0
count = 1
# 因为我们不知道什么时候数据才能爬完, 也就是说我们不知道什么时候结束, 所以我们这里会用死循环, 之后根据观察当没有数据的时候, 控制台会返回什么信息, 再做决定如何跳出循环。
while True:
    # url会变, 用刚才定义好的page参数代表url里面的start
    url = f'https://movie.douban.com/j/chart/top_list?type=10&interval_id=100%3A90&action=&start={page}&limit=20'
    # 请求头
    headers = {
        "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36"
    }
    response = requests.get(url, headers=headers)
    data = response.json()
    for i in data:
        # i = 第一次循环取出的是 列表种的第一个字典 对应的是一个电影信息
        # 电影名
        title = i['title']
        # 演员表
        actors = i['actors']
        # 评分
        score = i['score']
        # 上映时间
        release_date = i['release_date']
        print(count, "电影标题:", title, ", 演员列表:", actors, ", 评分", score, ", 上映时间", release_date)
        print(f"第{count}页数据已经全部提取完毕")
        count += 1
    page += 20
    print(data)
    # 无限循环什么时候结束? 数据没有了就应该结束
    # if len(data) == 0:
    #     print(f"第{count}页数据已经全部提取完毕")
    #     break

结果:

我们可以看到, 在265条数据以后, 都返回了空列表, 这就意味着数据到265条就结束了, 而且空列表的判断, 是判断data的长度是否为0(data的数据是列表里面套着字典,也就是[{},{}]这样的格式), 所以判断方法是if len(data) == 0。

同样的, 我们再看一个案例, 这个案例的判断爬虫是否结束的方法和上面的不一样了。

腾讯招聘网站分页:
代码:

python 复制代码
import requests

"""
pageIndex: 查看的数据是第几页数据
"""
page = 1
# 获取所有数据
while True:
    # 获取1到10页数据
    count = 1
    url = f"https://careers.tencent.com/tencentcareer/api/post/Query?timestamp=1726832959000&countryId=&cityId=&bgIds=&productId=&category=&parentCategory=&attrId=1&keyword=&pageIndex={page}&pageSize=10&language=zh-cn&area=cn"
    res = requests.get(url)
    # 打印每一条响应的数据, 目的是需要观察当响应不到数据的时候, 在控制台返回的是什么。
    print(res.text)
    data = res.json()
    # TypeError: 'NoneType' object is not iterable
    # {"Code":200,"Data":{"Count":0,"Posts":null}}
    # 根据数据响应的结果, 进行结束循环的判断
    if data["Data"]['Posts'] is None:
        break
    for i in data["Data"]['Posts']:
        # 岗位名称
        RecruitPostName = i['RecruitPostName']
        # 工作地点
        LocationName = i['LocationName']
        # 工作内容
        Responsibility = i['Responsibility']
        print(count, RecruitPostName, LocationName, Responsibility)
        count += 1
    print(f"第{page}页数据加载完毕")
    page += 1

结果:

我们可以发现, 利用分页爬虫可以在腾讯招聘网里面爬取246条数据。同时我们可以在控制台的最下方, 看到有{"Code":200,"Data":{"Count":0,"Posts":null}}, 我们看到了Posts是null, 那我们就知道, 判断爬虫是否结束, 需要怎么去判断它了, 那这里, 我们需要用到
if data["Data"]['Posts'] is None, 判断data["Data"]['Posts']是否为空作为判断爬虫是否结束。

将爬虫到的数据保存

这里, 我们先将数据保存到文本里面, 至于如何将数据保存到数据库或者excel等操作, 这些我们之后再讲。

其实, 把数据保存到文本里面非常的简单, 思路也很简单, 我们可以创建一个字符串变量, 那个变量就是用于存储爬虫的数据的, 最后我们将数据全部写入文件中。我们就那腾讯招聘的代码为例子。

由于字数限制, 无法在这篇文章里面继续写下去了, 给你们带来不便, 敬请谅解!!!

剩下的内容, 在下一篇文章里面了哦。

上一个
爬虫入门之爬虫原理以及请求响应
下一个
爬虫请求响应以及提取数据2
最近修改: 2024-09-24Powered by