python爬虫爬取使用Ajax请求的网站数据解析——以梅老板微博为例(m.weibo.cn)

2023-11-11

前言

前面学习了使用正则表达式和利用python第三方的解析库实现对目标网页源代码的爬取,可见即可爬,但很多时候往往并没有那么友好,网页源代码中可能没有我们需要的东西。还有当我们使用requesets抓取页面的时候,得到的结果可能和我们在浏览器中看到的结果不太一样,在浏览器中能看到正常的页面数据,但是使用requests爬取到的页面信息却不一样。这是因为requests获取到的是原始的HTML文本,而浏览器中的页面是经过JavaScript处理数据之后生成的结果。这种数据处理的方式有很多,可能是通过Ajax加载的,或者其他方式。通过Ajax加载的网页原始页面不会包含某些数据,等原始页面加载完成之后,会再向服务器请求接口获取数据,然后数据就被呈现在网页上。使用Ajax请求的网页一般有一个特点:下拉页面能源源不断的获取新的内容,不需要说是点击下一页才能看到其他数据,下拉页面之后新的内容就被加载出来了。下面我就介绍一下如何利用requests来模拟Ajax请求获取页面数据。

什么是Ajax

Ajax,全称Asynchronous Javascript and XML,即异步的JavaScript和XML。他不是一门编程语言,而是利用JavaScript在保证页面不被刷新、页面链接不改变的情况下与服务器交换数据并更新部分网页的技术。

对于传统的网页,我们要获取新内容,那么必须要刷新整个页面,但是Ajax就可以保证在页面不用全部刷新的情况下更新内容。在这个过程中,页面实际上是在后台与服务器进行了数据交互,获取到数据之后,再利用Javascript改变网页,然后就可以看到新的内容了。这就是我前面提到的只需要下拉页面就可以获取新的内容。

Ajax基本原理

发送Ajax请求到网页更新的这个过程可以分为以下三个步骤:

  • 发送请求
  • 解析内容
  • 渲染网页

发送请求

var xmlhttp;
if (window.XMLHttpRequest) {
    // code for IE7+, Firefox, Chrome, Opera, Safari
    xmlhttp=new XMLHttpRequest();
} else {// code for IE6, IE5
    xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange=function() {
    if (xmlhttp.readyState==4 && xmlhttp.status==200) {
        document.getElementById("myDiv").innerHTML=xmlhttp.responseText;
    }
}
xmlhttp.open("POST","/ajax/",true);
xmlhttp.send();

这是JavaScript对Ajax最底层的实现,实际上就是新建了XMLHttpRequest对象,然后调用onreadystatechange属性设置了监听,然后调用open()和send()方法向某个链接(也就是服务器)发送了请求。前面用Python实现请求发送之后,可以得到响应结果,但这里请求的发送变成JavaScript来完成.由于设置了监听,所以当服务器返回响应时,onreadystatechange对应的方法便会被触发,然后在这个方法里面解析响应内容即可。

解析内容

得到响应之后,onreadystatechange属性对应的方法便会被触发,此时利用xmlhttp的responseText属性便可取到响应内容。这类似于Python中利用requests向服务器发起请求,然后得到响应的过程。那么返回内容可能是HTML,可能是JSON,接下来只需要在方法中用JavaScript进一步处理即可。比如,如果是JSON的话,可以进行解析和转化。

渲染网页

JavaScript有改变网页内容的能力,解析完响应内容之后,就可以调用JavaScript来针对解析完的内容对网页进行下一步处理了。比如,通过document.getElementById().innerHTML这样的操作,便可以对某个元素内的源代码进行更改,这样网页显示的内容就改变了,这样的操作也被称作DOM操作,即对Document网页文档进行操作,如更改、删除等。
上例中,document.getElementById(“myDiv”).innerHTML=xmlhttp.responseText便将ID为myDiv的节点内部的HTML代码更改为服务器返回的内容,这样myDiv元素内部便会呈现出服务器返回的新数据,网页的部分内容看上去就更新了。
我们观察到,这3个步骤其实都是由JavaScript完成的,它完成了整个请求、解析和渲染的过程。

引用来源:https://cuiqingcai.com/5593.html
以上的部分大家可以作为一个了解,如果对JavaScript比较熟悉的同学应该能搞明白,反正我是不太懂的。

Ajax分析方法

查看请求

这里我们需要借助浏览器的开发者工具进行Ajax分析,下面以Chrome浏览器中梅老板的微博界面为例介绍一下如何进行Ajax分析。
首先在Chrome中打开链接https://m.weibo.cn/detail/4522545920873031,然后在加载好的页面右键单击,选择“检查",然后就能打开开发者工具。
在这里插入图片描述
切换到Network选项卡,然后点击中间那两栏我红笔标记的地方,然后刷新页面,找到第一个以getIndex开头的一个请求,然后在headers界面,往下翻会看到X-Requested-With: XMLHttpRequest,其中的XMLHttpRequest就代表这是一个Ajax请求。
在这里插入图片描述
然后切换到preview,就可以看到响应的内容,这里是json格式的,这里的Chrome为我们做了解析,然后看到的就是一个一个的键值对A : B。然后点击里面的箭头就可以看到一些主页的数据信息,JavaScript在接收到这些数据之后执行相应的渲染方法,整个页面就渲染出来了。

过滤请求

然后再利用开发者工具筛选出所有的Ajax请求,我们可以看到上面的筛选栏,然后点击XHR,此时下方现实的所有请求就是Ajax请求。
在这里插入图片描述
然后你可以点开每一个开头是getIndesx的请求,前面有的没有存数据,从后面的开始,每当你下拉页面就会有新的这个请求出来,然后里面就保存的有微薄的数据信息。然后我们只需要从这些数据中提取出我们想要的内容就可以了。

Ajax结果提取

我们仍以上面梅老板的微博为例,接下来我们利用python模拟Ajax请求,把梅老板发过的微博信息提取出来。

1.分析请求(since_id解析)

在这里插入图片描述
我们在Headers页面可以看到这个请求的各种参数信息,首先这是一个GET类型的请求,然后最后他的请求参数有四个type、value、containerid、since_id。然后再查看一下其他类似的请求发现这前三个参数所有的getIndex请求都是一样的,唯独这个since_id参数在每个请求的页面都不一样,并且还找不到什么规律,在我一筹莫展的时候,我有了如下发现:
在这里插入图片描述

上图我画红线的地方:首先界面上是我画黄色线条请求的接送数据页面,然后它里面的有一个cardlistInfo信息,然后里面就有这个since_id的值,然后观察可以看到,这个since_id的值就是下一个Ajax请求中url后面since_id的值。同理多看几个页面我们可以发现这么个规律:就是第一个以getIndex开头的Ajax请求的since_id为空,可以当作是0,但其请求数据中包含的有下一个请求的since_id值,然后后面的每一个since_id数据都在前一个请求所响应的JSON格式数据中,就这样所有的请求就都可以模拟得到。

2.分析响应

我们找到其中一个请求的preview界面,然后看到其内容是JSON格式的,然后浏览器开发者工具为我们做了解析便于查看,我们点开里面的每一个箭头,然后可以看到一些微博的信息,在mblog字段里面有attitude_count(点赞数)、comments_conunt(评论数)、reposts_count(转发数)、created_at(发布时间)、text(正文内容)等等数据。
在这里插入图片描述

3.爬取微博数据

首先,我们定义一个方法来获取每次请求的结果:

headers = {
    'host': 'm.weibo.cn',
    'Referer':'https://m.weibo.cn/u/5934019851',
    'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko)'
                            'Chrome/84.0.4147.89 Safari/537.36',
    'X-Requested-With': 'XMLHttpRequest',
    }
    
def get_page(since_id):
    params = {
        'type': 'uid',
        'value': '5934019851',
        'containerid': '1076035934019851',
    }
    if since_id != 0:
        params['since_id'] = since_id
    url = base_url + urlencode(params)
    try:
        response = requests.get(url, headers=headers)
        if response.status_code == 200:
            return response.json()
    except requests.ConnectionError as e:
        print("Error", e.args)

首先是要一个请求头,需要注意的是每台电脑中这个User-Agent是不一样的,然后在开发者工具中的Headers里面可以看到自己的User-Agent。然后构造一个字典,这个字典就能通过urlencode()方法转化为url中的请求参数,从而构成一个完整的url,其中的since_id我们单独定义并且要作为这个函数的参数,他是可变的,且可以通过其他方法求出。然后下面异常处理里面的代码就是一个非常常见的requests请求这个构造的链接,传入headers参数,然后返回json信息。
然后我们就需要定义一个解析方法了,从结果中提取出想要的信息,比如发布时间(created_at)、正文内容(text)、点赞数(attitude_count)、comments_conunt(评论数)、reposts_count(转发数)这几个内容。我们可以先遍历cards,然后获取mblog中的信息赋值为一个新的字典然后返回即可。

def parse_page(json):
    if json:
        items = json.get('data').get('cards')
        for item in items:
            item = item.get('mblog')
            weibo = {}
            weibo['time'] = item.get('created_at')
            weibo['text'] = pq(item.get('text')).text()
            weibo['attitudes'] = item.get('attitudes_count')
            weibo['comments'] = item.get('comments_count')
            weibo['reposts'] = item.get('reposts_count')
            yield weibo

其中由于text里面有很多的HTML文本标签,所以我们借助pyquery中的text()方法将不含标签的文本提取出来。
最后就是main函数的编写了,此处需要注意的一点就是since_id的表示和调用关系。

if __name__ == '__main__':
    since_id = 0
    for page in range(1, 11):
        json = get_page(since_id)
        since_id = json.get('data').get('cardlistInfo').get('since_id')
        results = parse_page(json)
        for result in results:
            print(result)

首先我们定义since_id为0,这表示是第一个Ajax请求,由于不存在上一个请求,所以设置初值为0,然后就是一个for循环,这里的page没有实际含义,不是原来崔庆才老师里面的那个page,原书中的page是因为微博的请求参数是page,现在改成了since_id。json = get_page(since_id)这行代码是解析出第一个Ajax请求的json信息,然后下一个请求的since_id可以在这个json数据中提取出来,然后解析得到我们想要的那几个数据并打印出来,然后下一次循环,又得到一个请求,这样不断地爬取微博数据。其实这里面的since_id就是原来的page,只不过有点麻烦需要我们去找。到此这个爬虫程序就差不多写完了。
完整代码:

import requests
from urllib.parse import urlencode
base_url = 'https://m.weibo.cn/api/container/getIndex?'
from pyquery import PyQuery as pq

headers = {
    'host': 'm.weibo.cn',
    'Referer':'https://m.weibo.cn/u/5934019851',
    'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko)'
                            'Chrome/84.0.4147.89 Safari/537.36',
    'X-Requested-With': 'XMLHttpRequest',
    }

def get_page(since_id):
    params = {
        'type': 'uid',
        'value': '5934019851',
        'containerid': '1076035934019851',
    }
    if since_id != 0:
        params['since_id'] = since_id
    url = base_url + urlencode(params)
    try:
        response = requests.get(url, headers=headers)
        if response.status_code == 200:
            return response.json()
    except requests.ConnectionError as e:
        print("Error", e.args)

def parse_page(json):
    if json:
        items = json.get('data').get('cards')
        for item in items:
            item = item.get('mblog')
            weibo = {}
            weibo['time'] = item.get('created_at')
            weibo['text'] = pq(item.get('text')).text()
            weibo['attitudes'] = item.get('attitudes_count')
            weibo['comments'] = item.get('comments_count')
            weibo['reposts'] = item.get('reposts_count')
            yield weibo


if __name__ == '__main__':
    since_id = 0
    for page in range(1, 11):
        json = get_page(since_id)
        since_id = json.get('data').get('cardlistInfo').get('since_id')
        results = parse_page(json)
        for result in results:
            print(result)

注:如果向copy过去自己运行的话需要修改headers里面的User_Agent信息。
部分运行结果:
在这里插入图片描述

后记

因为是按照崔庆才老师的爬虫书来学的,他这个书写的有一点早,好像是18年,很多的东西跟现在都不一样了,包括里面请求的内容啥的,最重要的一点是请求的参数不同,就是原来的那个page变成了since_id,刚开始的时候真的是一筹莫展,随说原来的代码也能够运行,但是总感觉哪里怪怪的,然后我就想办法用since_id代替page,中间的过程用了蛮久,但是最后解决了还是很nice的,最重要的是思想,思想是对的,在整理一些细节的地方就能够完美的解决问题了。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

python爬虫爬取使用Ajax请求的网站数据解析——以梅老板微博为例(m.weibo.cn) 的相关文章

随机推荐

  • BF算法与KMP模式匹配算法(画图详解,C语言实现)

    KMP算法 1 BF算法 1 1BF算法定义 1 2BF算法举例 1 3BF算法代码实现 1 4BF算法性能分析 2 KMP算法 2 1KMP算法与BF算法的区别 2 2求KMP算法next数组 2 3KMP算法的过程举例 2 4KMP算法
  • attr 和 prop 的区别介绍

    attr 和 prop 的区别介绍 对于 HTML 元素本身就带有的固有属性 在处理时 使用 prop 方法 对于 HTML 元素我们自己自定义的 DOM 属性 在处理时 使用 attr 方法 实例 1 a href https www r
  • Cesium设置时间类

    场景时钟类 export default class SceneClock viewer multiplier constructor viewer this viewer viewer 设置场景时钟 param start 开始时间 pa
  • vue+cesium汉化包

    把这个js放进你的项目里面然后调用就可以 我这个是vue项目 然后运用的是es6的导出语法 cesium 可视化部分的中文汉化 包含内容如下 1 汉化方式非从源码层面进行 而是外挂了一个插件执行 使用方便 但是汉化程度不深 只汉化了cesi
  • Introducing Language Guidance in Prompt-based Continual Learning

    本文是LLM系列文章 针对 Introducing Language Guidance in Prompt based Continual Learning 的翻译 基于提示的持续学习中引入语言指导 摘要 1 引言 2 相关工作 3 背景
  • IDE 之 Eclipse安装

    目录 前言 一 Eclipse是什么 二 Eclipse优缺点 1 优点 2 缺点 三 安装Eclipse 1 官方下载Eclipse 2 安装Eclipse 3 运行eclipse 3 1 进入欢迎页面 前言 对于学习java的人来说 E
  • PTA(浙大版《C语言程序设计(第3版)》题目集)习题6-4 使用函数输出指定范围内的Fibonacci数 (20 分)

    PTA 浙大版 C语言程序设计 第3版 题目集 习题6 4 使用函数输出指定范围内的Fibonacci数 20 分 本题要求实现一个计算Fibonacci数的简单函数 并利用其实现另一个函数 输出两正整数m和n 0
  • [科普] 狭义相对论

    本文转载至 http www dlkp gov cn keputiandi universe article dispArticle Asp ID 58 第一章 狭义相对论 一 狭义相对论思想的根源 1 法拉第 麦克斯维将电磁学推向 场 的
  • 支付宝小程序框架分析

    支付宝小程序框架逆向分析 本文对支付宝小程序的正向开发做了简单介绍 并从正向开发的文件类型入手 对小程序的宿主框架进行了逆向分析 包括运行机制 通信模型以及安全防护体系等内容 代码开发 支付宝小程序开发在语法方面与传统的前端网页开发非常类似
  • Python——发送邮件

    一 smtplib模块 主要通过SMTP类与邮件系统进行交互 使用方法如下 1 实例化一个SMTP对象 s smtplib SMTP 邮件服务地址 端口号 s smtplib SMTP SSL 邮件服务地址 端口号 2 登陆邮件 权限验证
  • Linux:全志H3图像codec使用笔记

    1 前言 限于作者能力水平 本文可能存在谬误 因此而给读者带来的损失 作者不做任何承诺 2 图像 codec 概述 图像编解码器 codec 包含 Encoder 和 Decoder 两部分功能 我们用下列分别说明 Encoder 和 De
  • 解决window平台下cocos creator 构建发布面板打开后无法显示问题

    项目场景 creator构建发布界面 问题描述 window平台下cocos creator 构建发布面板打开后无法显示 原因分析 项目的配置文件目录setting和local目录内容混乱可能会导致该问题 这时候后重装creator也是没用
  • 设计模式全解析(一)——带你搞懂设计模式

    各位朋友 一提到 设计模式 四个字 是不是有一种若隐若现的朦胧感 我知道设计模式 我知道单例 工厂 观察者 策略 但是设计模式到底是什么呢 解决了什么问题呢 接下来我会一步一步解析一下设计模式 以及各个不同的设计模式到底要做的是什么 我们先
  • Octave的一些基本操作和语法,快速上手Octave,用实例解释

    基本语法 1 直接计算 gt gt 1 2 ans 3 2 变量计算 在最后加上分号 可以不输出结果 gt gt a 1 gt gt b 2 gt gt a b ans 3 3 矩阵赋值 gt gt a 1 2 3 4 5 6 a 1 2
  • Java实现五子棋小游戏(附源码)

    一 效果展示 二 游戏介绍 五子棋 是一种两人对弈的纯策略型棋类游戏 棋具与围棋通用 是起源于中国古代的传统黑白棋种之一 发展于日本 流行于欧美 容易上手 老少皆宜 而且趣味横生 引人入胜 不仅能增强思维能力 提高智力 而且富含哲理 有助于
  • [ Linux ] 静态代码检测工具 —— Cppcheck工具

    文章目录 cppcheck工具介绍 Linux安装 linux使用示例 在makefile中添加cppcheck工具实例 cppcheck工具介绍 什么是静态代码检查 静态代码检查是指在不运行程序的条件下 进行程序分析的方法 有些程序分析需
  • Git 分支管理策略汇总

    原文链接 Git 分支管理策略 最近 团队新入职了一些小伙伴 在开发过程中 他们问我 Git 分支是如何管理的 以及应该怎么提交代码 我大概说了一些规则 但仔细想来 好像也并没有形成一个清晰规范的流程 所以查了一些资料 总结出下面这篇文章
  • 企业如何制定实施MES管理系统的预算方案

    随着制造业的不断发展 MES生产管理系统逐渐成为制造企业提高生产效率 优化资源利用和提升质量水平的重要工具 制定实施MES管理系统的预算方案是企业在进行MES选型和实施时必须考虑的问题 本文将介绍制定实施MES管理系统预算方案的关键步骤 包
  • Nginx常用功能(配置静态资源)

    Nginx配置静态资源 背景 现场业务系统域名均由nginx转发 需求 通过nginx设置静态访问页面 操作如下 1 将静态文件存放在 opt nginx html 下 2 修改nginx conf文件 引用此静态文件 server lis
  • python爬虫爬取使用Ajax请求的网站数据解析——以梅老板微博为例(m.weibo.cn)

    文章目录 前言 什么是Ajax Ajax基本原理 发送请求 解析内容 渲染网页 Ajax分析方法 查看请求 过滤请求 Ajax结果提取 1 分析请求 since id解析 2 分析响应 3 爬取微博数据 后记 前言 前面学习了使用正则表达式