Python编程—Ajax数据爬取

Python编程—Ajax数据爬取

​ 在浏览器中可以看到正常显示的页面数据,而使用requests得到的结果中并没有这些数据。这是因为requests获取的都是原始HTML文档,而浏览器中的页面是JavaScript处理数据后生成的结果,这些数据有多种来源:可能是通过Ajax加载的,可能是包含在HTML文档中的,也可能是经过JavaScript和特定算法计算后生成的。

对第一种来源,数据加载是一种异步加载方式,原始页面最初不会包含某些数据,当原始页面加载完后,会再向服务器请求某个接口获取数据,然后数据才会经过处理从而呈现在网页上,这其实是发送了一个Ajax请求。使得web开发做到前后端分离,减小服务器直接渲染页面带来的压力。

所以遇到这样的页面,直接利用requests等库来抓取原始HTML文档,是无法获取有效数据的。这时需要分析网页后台接口发送的Ajax请求。如果可用requests模拟Ajax请求,就可以成功抓取网页数据了。

5.1 什么是Ajax

AJAX 是一种在无需重新加载整个网页的情况下,能够更新部分网页的技术。它基于 HTML、CSS、JavaScript、XML 和 XMLHttpRequest 等标准。

首先,AJAX 的全称是 Asynchronous JavaScript and XML(异步的JavaScript和XML),它是一种用于创建更好更快以及交互性更强的Web应用程序的技术。使用 JavaScript 向服务器提出请求并处理响应而不阻塞用户的核心对象是 XMLHttpRequest。

其次,AJAX 的主要优点是可以在不刷新整个网页的情况下,对网页的某部分进行更新。这样可以提高网页的响应速度和用户体验,因为它避免了每次用户操作都需要等待整个页面重新加载的情况。

最后,AJAX 的应用场景非常广泛,包括但不限于表单提交、数据检索、实时消息更新等。通过使用 XMLHttpRequest 对象和回调函数,可以实现局部刷新,从而检测用户输入的用户名是否为"zhongfucheng"。

  1. 实例引入

微博主页https://m.weibo.cn/u/2830678474为例。

  1. 基本原理

    简单分为3步——发送请求、解析内容、渲染网页。

    • 发送请求

      JavaScript可以实现页面的各种交互功能,Ajax也不例外,它也是由JavaScript实现的,实现代码如下:

      var xmlhttp;
      if (window.XMLHttpRequest) {xmlhttp = new XMLHttpRequest();
      }else {//code for IE6、IE5xmlhttp=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对象xmlhttp,然后调用onreadystatechange属性设置监听,最后调用open和send方法向某个链接(服务器)发送请求。这里的请求发送由JavaScript完成,不是Python实现。由于设置了监听,所以当服务器返回响应时,onreadystatechange对应的方法便会被触发,然后在这方法里面解析响应内容即可。

    • 解析内容

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

    • 渲染网页

    JavaScript有改变网页内容的能力,因此解析完响应内容后,就可以调用JavaScript来基于解析完的内容对网页进行下一步处理了。例如,通过document.getElementById().innerHTML操作,可以更改某个元素内的源代码,这样网页显示的内容就改变了。这种操作也被称为DOM操作,即对网页文档进行操作,如更改、删除等。

    上面“发送请求”部分,代码里的document.getElementById(”myDiv”).innerHTML=xmlhttp.responseText便是将ID为myDiv的节点内部的HTML代码更改为服务器返回的内容,这样myDiv元素内部便会呈现服务器返回的新数据,对应的网页内容看上去就更新了。

5.2 Ajax分析方法

  1. 分析案例

用Chrome浏览器打开微博链接https://m.weibo.cn/u/2830678474,然后在页面中单击鼠标右键,从弹出的快捷菜单中选择“检查”选项,此时便会弹出开发者工具,如图所示:

Screenshot 2024-03-22 at 22.10.05

Screenshot 2024-03-23 at 09.28.54

Ajax尤其特殊请求类型叫做xhr,可以发现一个名称以getIndex开头的请求,其Type就为xhr,意味着这就是一个Ajax请求。用鼠标单击这个请求,可以查看其详细信息。其中Request Headers中有一个信息为X-Rrequested-With:XMLHttpRequest,这就标记了此请求是Ajax请求,如图所示:

3

随后单击一下Preview, 就能看到响应内容,如图所示,内容是JSON格式的,这里Chrome为我们自动做了解析,单击左箭头即可展开和收起相应内容。

4

经过观察可以发现,这里的返回结果是我的个人信息,如昵称、简介、头像等,这也是渲染个人主页使用的数据。JavaScript接收到这些数据之后,再执行相应的渲染方法,整个页面就渲染出来。

5

也可以切换到Response选项卡,从中观察真实的返回数据,如图所示:

6

接下来,切回第一个请求,观察一下它的Response是什么,如图所示:

7

原始的链接https://m.weibo.cn/u/2830678474返回的结果,其代码只有不到50行,结构也非常简单,只是执行了一些JavaScript语句。所以说,微博页面呈现给我们的真实数据并不是最原始的页面返回的,而是执行JavaScript后再次向后台发送Ajax请求,浏览器拿到服务器返回到数据后进一步渲染得到的。

  1. 过滤请求

利用Chrome开发者工具的筛选功能能够筛选出所有Ajax请求。在请求的上方有一层筛选栏,直接单击XHR,之后下方显示的所有请求便都是Ajax请求了,如图所示:

8

接下来只需要用程序模拟这些Ajax请求,就可以轻松提取我们所需的信息。

5.3 Ajax分析与爬取实战

  1. 准备工作
    • 安装好Python3(最低为3.6版本),并成功运行Python3程序。
    • 了解Python HTTP请求库requests的基本用法。
    • 了解Ajax基础知识和分析Ajax的基本方法。
  2. 爬取目标

示例网站链接:https://spa1.scrape.center/,该示例网站的数据请求是通过Ajax完成的,页面的内容是通过JavaScript渲染出来的,页面如图所示。

9

单击每部电影进入对应的详情页,这些页面的结构也是完全一样的,如下图所示的是《迁徙的鸟》的详情页。

10

完成目标如下:

  • 分析页面数据的加载逻辑
  • 用requests实现Ajax数据的爬取
  • 将每部电影的数据分别保存到MongoDB数据库
  1. 初步探索

先尝试用requests直接提取页面,看看结果。实现代码如下:

import requestsurl = '<https://spa1.scrape.center/>'
html = requests.get(url).text
print(html)运行结果如下:
<!DOCTYPE html><html lang=en><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge">
<meta name=viewport content="width=device-width,initial-scale=1"><link rel=icon href=/favicon.ico><title>Scrape | Movie</title>
<link href=/css/chunk-700f70e1.1126d090.css rel=prefetch><link href=/css/chunk-d1db5eda.0ff76b36.css rel=prefetch>
<link href=/js/chunk-700f70e1.0548e2b4.js rel=prefetch><link href=/js/chunk-d1db5eda.b564504d.js rel=prefetch>
<link href=/css/app.ea9d802a.css rel=preload as=style><link href=/js/app.17b3aaa5.js rel=preload as=script>
<link href=/js/chunk-vendors.683ca77c.js rel=preload as=script><link href=/css/app.ea9d802a.css rel=stylesheet>
</head><body><noscript><strong>We're sorry but portal doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
</noscript><div id=app></div><script src=/js/chunk-vendors.683ca77c.js></script><script src=/js/app.17b3aaa5.js></script>
</body></html>

可以看到,爬取结果只有这么一点HTML内容,在HTML中只能看到源码引用的一些JavaScript和CSS文件,没有观察到任何电影数据信息。这说明浏览器执行了HTML中引用的JavaScript文件,通过调用一些数据加载和页面渲染方法,才最终呈现页面显示的结果。JavaScript在后台调用Ajax数据接口,得到数据之后,再对数据进行解析并渲染呈现出来。所以直接爬取Ajax接口,再获取数据就好了。

  1. 爬取列表页

首先分析列表页的Ajax接口逻辑,打开浏览器开发者工具,切换到Network面板,勾选Preserve Log并切换到XHR选项卡,接着重新刷新页面,再单击第3页、第4页的按钮,开发者工具下方页也监听到了几个Ajax请求,如图所示:

11

每次翻页也出现了对应的Ajax请求,可以单击查看其请求详情,观察请求URL、参数和响应内容是怎么样的,如图所示:

12

点开最后一个结果,观察到Ajax接口的请求UR为https://spa1.scrape.center/api/movie/?limit=10&offset=30。

观察多个Ajax接口的参数,可以总结一个规律:limit一直为10,正好对应每页10条数据;offset在依次变大,页数每加1,offset就加10,因此其代表页面的数据偏移量。

接着观察一下响应内容,切换到Preview选项卡,如下图所示:

13

可以看到,结果就是一些JSON数据,其中有一个results字段,是一个列表,列表中每一个元素都是一个字典。观察一下字典的内容,正好是对应电影数据的字段,如name、alias、cover、categories。爬取详情页和爬取列表页的代码如下:

import loggingimport requestslogging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s : %(message)s')LIMIT = 10# 定义一个通用爬取方法
def scrape_api(url):logging.info('scraping %s...', url)try:response = requests.get(url)if response.status_code == 200:return response.json()logging.error('get invalid status code %s while scraping %s', response.status_code, url)except requests.RequestException:logging.error('error occurred while scraping %s', url, exc_info=True)# 爬取列表页的方法
def scrape_index(page):url = f'<https://spa1.scrape.center/api/movie/?limit={LIMIT}&offset={LIMIT*(page-1)}>'return scrape_api(url)
  1. 爬取详情页

单击任意一部电影,如《肖申克的救赎》,进入其详情页,可以发现此时的页面URL已经变成了https://spa1.scrape.center/detail/3,页面也成功展示了《肖申克的救赎》详情页的信息,如下图所示:

14

另外,我们也可以观察到开发者工具中又出现了一个Ajax请求,其URL为 https://spa1.scrape.center/api/movie/3,通过Preview选项卡也能看到Ajax请求对应的响应信息,如图所示:

15

  进一步观察发现,列表页原本返回数据中就带有id这个字段,所以只要拿列表页结果中的id来构  造详情页的Ajax请求的URL就好了。定义一个详情页的爬取逻辑,代码如下:
# 详情页爬取方法
def scrape_detail(id):url = f'<https://spa1.scrape.center/api/movie/{id}>'return scrape_api(url)
最后,定义一个总调用方法,对以上方法串联调用,代码如下:
def main():for page in range(1, TOTAL_PAGE+1):index_data = scrape_index(page)for item in index_data.get('results'):id = item.get('id')detail_data = scrape_detail(id)logging.info('detail data %s', detail_data)if __name__ == '__main__':main()运行结果如下(省略部分内容):

….

2024-03-23 13:28:19,493 - INFO : detail data {‘id’: 21, ‘name’: ‘黄金三镖客’, ‘alias’: ‘Il buono, il brutto, il cattivo.’, ‘cover’: ‘https://p0.meituan.net/movie/cd18ed2c5cda9e71e17e5e6ef61ced172912303.jpg@464w_644h_1e_1c’, ‘categories’: [‘西部’, ‘冒险’], ‘regions’: [‘意大利’, ‘西班牙’, ‘西德’], ‘actors’: [{‘name’: ‘克林特·伊斯特伍德’, ‘role’: ‘布兰迪 Blondie’, ‘image’: ‘https://p1.meituan.net/moviemachine/d1156c14dd899ada7c2b98bc373021c852875.jpg@128w_170h_1e_1c’}, {‘name’: ‘李·范·克里夫’, ‘role’: ‘桑坦萨 Sentenza’, ‘image’: ‘https://p0.meituan.net/movie/665eab6fdb7755138e0c8092f35ba39327553.jpg@128w_170h_1e_1c’}, {‘name’: ‘埃里·瓦拉赫’, ‘role’: ‘图科 Tuco’, ‘image’: ‘https://p1.meituan.net/movie/275042f2bbe012263b8deed1c96e611b42623.jpg@128w_170h_1e_1c’}, {‘name’: ‘路易吉·皮斯蒂利’, ‘role’: ‘Father Pablo Ramirez’, ‘image’: ‘https://p1.meituan.net/movie/3c91cd5186e89e927056adbc8a722f5014760.jpg@128w_170h_1e_1c’}, {‘name’: ‘Claudio Scarchilli’, ‘role’: ‘Bounty Hunter in Ghost Town’, ‘image’: ‘https://p1.meituan.net/mmdb/3a2061d771d98566d3e5fa5c08c5e0b33685.png@128w_170h_1e_1c’}, {‘name’: ‘John Bartha’, ‘role’: ‘Sheriff (as John Bartho)’, ‘image’: ‘https://p1.meituan.net/mmdb/3a2061d771d98566d3e5fa5c08c5e0b33685.png@128w_170h_1e_1c’}, {‘name’: ‘Livio Lorenzon’, ‘role’: ‘Baker’, ‘image’: ‘https://p1.meituan.net/mmdb/3a2061d771d98566d3e5fa5c08c5e0b33685.png@128w_170h_1e_1c’}, {‘name’: ‘贝尼托·斯特凡内利’, ‘role’: “Member of Angel Eyes’ Gang”, ‘image’: ‘https://p0.meituan.net/movie/69698bc0960b07e3acddd412f3b88ee821953.jpg@128w_170h_1e_1c’}, {‘name’: ‘Angelo Novi’, ‘role’: ‘Monk’, ‘image’: ‘https://p1.meituan.net/mmdb/3a2061d771d98566d3e5fa5c08c5e0b33685.png@128w_170h_1e_1c’}, {‘name’: ‘安东尼奥·卡萨斯’, ‘role’: ‘Stevens’, ‘image’: 'https://p1.meituan

……

至此,所有电影详情数据,都爬取到了。

  1. 保存数据

​ 请确保有一个可以正常连接和使用的MongoDB数据库,这里以本地localhost的MongoDB数据库为例来进行操作,其运行在27017端口上,无用户名和密码。

将数据导入MongodDB需要用到PyMongo这个库,配置如下:

import pymongo# 定义常量
MONGO_CONNECTION_STRING = 'mongodb://localhost:27017'
MONGO_DB_NAME = 'movies'
MONGO_COLLECTION_NAME = 'movies'client = pymongo.MongoClient(MONGO_CONNECTION_STRING)
db = client['movies']
collection = db['movies']

定义一个将数据保存到MongoDB数据库的方法,代码如下:

# 定义保存数据到MongoDB的方法
def save_data(data):collection.update_one({'name':data.get('name')},{'$set':data}, upsert=True)

接下来改写一下main方法,如下所示:

def main():for page in range(1, TOTAL_PAGE + 1):index_data = scrape_index(page)for item in index_data.get('results'):id = item.get('id')detail_data = scrape_detail(id)logging.info('detail data %s', detail_data)save_data(detail_data)logging.info('data saved successfully')

其实就是增加了save_data方法调用,并添加一些日志信息。重新运行,看看输出结果:

16

可以看到,数据就是以JSON格式存储的,一条数据对应一部电影信息,各种嵌套关系也是一目了然。

以上示例的一些库的详细操作可以在[小蜜蜂AI网站][https://zglg.work]体验。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/767375.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用 Suno 创作歌曲

Suno 是一款基于人工智能的音乐创作工具&#xff0c;可以帮助您轻松创作原创歌曲。 它可以根据您的歌词生成旋律、和弦和伴奏&#xff0c;并提供多种风格和情绪供您选择。 在本文中&#xff0c;我们将介绍如何使用 Suno 创作歌曲。 我们将使用以下步骤&#xff1a; 选择客制化…

windows 系统下(nacos1.x) nacos-1.1.3 链接数据库 mysql8.0 出错分析

** windows 系统下&#xff08;nacos1.x&#xff09; nacos-1.1.3 链接数据库 mysql8.0 出错分析 ** 1、首先以下方法亲测无效&#xff1a; 1&#xff09;需要在数据库 URL 链接配置信息中 添加 allowPublicKeyRetrievaltrue 无效 db.url.0**&allowPublicKeyRetrievalt…

算法-最短路径

图的最短路径问题是一个经典的计算机科学和运筹学问题&#xff0c;旨在找到图中两个顶点之间的最短路径。这种问题在多种场景中都有应用&#xff0c;如网络路由、地图导航等。 解决图的最短路径问题有多种算法&#xff0c;其中最著名的包括&#xff1a; 1.迪杰斯特拉算法 (1).…

AWTK T9 输入法实现原理

1. T9 输入法的中文字典数据 网上可以找到 T9 输入法的中文字典数据&#xff0c;但是通常有两个问题&#xff1a; 采用 GPL 协议&#xff0c;不太适合加入 AWTK。 只支持单个汉字的输入&#xff0c;不支持词组的输入。 经过考虑之后&#xff0c;决定自己生成 T9 输入法的中…

Mamba复现与代码解读

文章目录 环境配置demo推理源码解析参数解读Mamba块&#xff08;Mamba Block&#xff09;状态空间模型(SSM)选择性扫描算法&#xff08;selective_scan&#xff09;前向传播&#xff08;forward&#xff09; 均方根归一化 &#xff08;RMSNorm&#xff09;残差块&#xff08;Re…

集成学习 | 集成学习思想:Boosting

目录 一. Boosting思想1. Adaboost 算法1.1 Adaboost算法构建流程1.2 sklearn库参数说明 2. Gradient Boosting 算法2.1 Gradient Boosting算法构建流程2.2 Gradient Boosting算法的回归与分类问题2.2.1 Gradient Boosting回归算法均方差损失函数绝对误差损失函数 2.2.2 Gradie…

【Linux】进程地址空间详解

前言 在我们学习C语言或者C时肯定都听过老师讲过地址的概念而且老师肯定还会讲栈区、堆区等区域的概念&#xff0c;那么这个地址是指的物理内存地址吗&#xff1f;这里这些区域又是如何划分的呢&#xff1f; 我们在使用C语言的malloc或者C的new函数开辟空间时&#xff0c;开辟…

解锁隐私计算力量:一站式掌握SecretFlow安装与双模式部署实践

1.SecretFlow的安装 1.SecretFlow运行要求 SecretFlow作为一个隐私保护的数据分析和机器学习框架&#xff0c;其运行要求可能涉及以下方面&#xff1a; 操作系统&#xff1a; 能够支持Docker运行的环境&#xff0c;因为SecretFlow可能通过Docker容器来管理执行环境的一致性和…

Python Flask 自定义404错误

from flask import Flask, abort, make_response, request, render_templateapp Flask(__name__)# 重定向到百度 app.route(/index, methods["GET", "POST"]) def index():if request.method "GET":return render_template("index.html&q…

推荐一款制造执行系统(MES)国内比较好的实施厂家

什么是MES 制造执行系统&#xff08;MES&#xff09;是一种用于监控、控制和优化制造过程的软件系统。它通过与企业资源计划&#xff08;ERP&#xff09;系统和自动化系统的集成&#xff0c;实现对生产过程的管理和监测&#xff0c;包括生产计划、生产过程和生产数据。 MES可…

BUG未解之谜01-指针引用之谜

在leetcode里面刷题出现的问题&#xff0c;当我在sortedArrayToBST里面给root赋予初始值NULL之后&#xff0c;问题得到解决&#xff01; 理论上root是未初始化的变量&#xff0c;然后我进入insert函数之后&#xff0c;root引用的内容也是未知值&#xff0c;因此无法给原来的二叉…

鸿蒙开发学习【地图位置服务组件】

简介 移动终端设备已经深入人们日常生活的方方面面&#xff0c;如查看所在城市的天气、新闻轶事、出行打车、旅行导航、运动记录。这些习以为常的活动&#xff0c;都离不开定位用户终端设备的位置。 当用户处于这些丰富的使用场景中时&#xff0c;系统的位置定位能力可以提供…

【Python】基础语法(一)

文章目录 1.注释2.关键字与标识符2.1关键字2.2标识符 3.变量4.数据类型4.1数字类型4.2类型转换函数4.3布尔类型 5.输入(input)与输出(print)5.1输入函数(input)5.2输出函数(print) 6.运算符6.1算术运算符6.2比较运算符6.3赋值运算符6.4逻辑运算符6.5运算符优先级 7.字符串7.1字…

JMH微基准测试框架学习笔记

一、简介 JMH&#xff08;Java Microbenchmark Harness&#xff09;是一个用于编写、构建和运行Java微基准测试的框架。它提供了丰富的注解和工具&#xff0c;用于精确控制测试的执行和结果测量&#xff0c;从而帮助我们深入了解代码的性能特性。 二、案例实战 在你的pom文件…

MySQL 排序的那些事儿

书接上回 上次发了几张图&#xff0c;给了几个MySQL Explain的场景&#xff0c;链接在这儿&#xff1a;你是不是MySQL老司机&#xff1f;来看看这些explain结果你能解释吗&#xff1f;MySQL 夺命6连问 我们依次来分析下这6个问题。 在分析之前&#xff0c;我们先来了解一下M…

操作系统面经-用户态和内核态

字节实习生带你面试&#xff0c;后台私信可以获得面试必过大法&#xff01;&#xff01; 根据进程访问资源的特点&#xff0c;我们可以把进程在系统上的运行分为两个级别&#xff1a; 用户态(User Mode) : 用户态运行的进程可以直接读取用户程序的数据&#xff0c;拥有较低的…

【蓝牙协议栈】【BLE】低功耗蓝牙配对绑定过程分析(超详细)

1. 精讲蓝牙协议栈&#xff08;Bluetooth Stack&#xff09;&#xff1a;SPP/A2DP/AVRCP/HFP/PBAP/IAP2/HID/MAP/OPP/PAN/GATTC/GATTS/HOGP等协议理论 2. 欢迎大家关注和订阅&#xff0c;【蓝牙协议栈】和【Android Bluetooth Stack】专栏会持续更新中.....敬请期待&#xff01…

Three.js 中的 OrbitControls 是一个用于控制相机围绕目标旋转以及缩放、平移等操作的控制器。

demo案例 Three.js 中的 OrbitControls 是一个用于控制相机围绕目标旋转以及缩放、平移等操作的控制器。下面是它的详细讲解&#xff1a; 构造函数: OrbitControls(object: Camera, domElement?: HTMLElement)object&#xff1a;THREE.Camera 实例&#xff0c;控制器将围绕…

从零开始学习在VUE3中使用canvas(五):globalCompositeOperation(图形混合)

一、简介 通过设置混合模式来改变图像重叠区域的显示方式。 const ctx canvas.getContext("2d");ctx.globalCompositeOperation "source-over"; 二、属性介绍 source-over 这是默认的复合操作。将源图像绘制到目标图像上&#xff0c;保留目标图像的不透…

IPV6协议之DHCPV6

目录 背景&#xff1a; 一、DHCPV6概述 DHCPv6 Client&#xff1a; DHCPv6 Relay&#xff1a; DHCPv6 Server&#xff1a; 二、DHCPV6工作原理 DHCPV6无状态自动分配 三、DHCP基础配置 服务端 四、DHCPV6地址更新时间&#xff08;DHCPV4租期&#xff09; 五、DHCPV6…