第5章 Ajax数据爬取

news/2024/7/19 8:38:24 标签: python, 爬虫

目录

  • 1. 什么是Ajax
    • 1.1 实例引入
    • 1.2 基本原理
      • 发送请求
      • 解析内容
      • 渲染网页
  • 2. Ajax分析方法
    • 2.1 分析案例
    • 2.2 过滤请求
  • 3. Ajax分析与爬取实战
    • 3.1 爬取目标
    • 3.2 初步探索
    • 3.3 爬取列表页
      • 分析
      • 实现
        • 基础配置
        • 爬取页面内容(获取页面的JSON内容)
        • 爬取列表页(爬取指定列表页)
      • 合并
    • 3.4 爬取详情页
      • 分析
      • 实现
        • 爬取详情页
        • 串联调用
      • 合并
    • 3.5 保存数据(MongoDB)(后期补充)

  • 使用requests获取的是原始HTML文档
  • 浏览器中的页面是JavaScript处理数据后生成的结果
  • 数据的来源
    • 通过Ajax加载
    • 包含在HTML文档中
    • 经过JavaScript和特定算法计算后生成
  • Ajax加载数据
    • 方式:异步
      • 原始页面最初不包含某些数据
      • 当原始页面加载成功后,再向服务器请求某个接口获取数据
        • 发送Ajax请求
      • 然后将数据处理并呈现在网页上

1. 什么是Ajax

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

1.1 实例引入

  • 下滑查看更多
  • 下滑后加载的动画:Ajax 加载的过程

1.2 基本原理

  • 从Ajax请求到网页更新的这个过程可以分为3步
    • 发送请求
    • 解析内容
    • 渲染网页

发送请求

  • JavaScript对Ajax最底层的实现
var xmlhttp;
if (window.XMLHttpRequest) {
    xmlhttp = new XMLHttpRequest();
} else {
    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();

解析内容

var xmlhttp;
if (window.XMLHttpRequest) {
    xmlhttp = new XMLHttpRequest();
} else {
    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();

渲染网页

var xmlhttp;
if (window.XMLHttpRequest) {
    xmlhttp = new XMLHttpRequest();
} else {
    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();

2. Ajax分析方法

2.1 分析案例

  • 微博 (weibo.cn)
  • Ajax 的请求类型:xhr
  • 如果 Request Headers 中有一个信息为XMLHttpRequest,则此请求就是 Ajax 请求
    • 以 getIndex 开头的请求
  • 可以在 Preview 查看响应的内容
  • 也可以在 Response 查看真实返回的数据

2.2 过滤请求

  • 点击 Network 中的 XHR 选项,显示所有的 Ajax 请求

3. Ajax分析与爬取实战

  • 爬取 Scrape | Movie
    • 与 2.5(Scrape | Movie)不同
      • 数据请求是通过 Ajax 实现的
      • 页面内容通过 JavaScript 渲染出来的
      • 只是呈现样式是一样的

3.1 爬取目标

  • 爬取电影的名称、封面、类别、上映时间、评分、剧情简介等内容
  • 分析页面数据的加载逻辑
  • 用 requests 实现 Ajax 数据的爬取
  • 将每部电影数据分别保存到 MongoDB 数据库

3.2 初步探索

python">import requests

url = "https://spa1.scrape.center/"
html = requests.get(url).text

print(html)
  • 获取到的 html 资源较少
  • 整个页面都是JavaScript渲染得到的,浏览器执行了HTML中引用的JavaScript文件,JavaScript通过调用一些数据加载和页面渲染方法,才最终呈现出浏览器中的显示效果
  • 数据一般是通过Ajax加载的,JavaScript在后台调用Ajax数据接口

3.3 爬取列表页

分析

  • 请求URL的limit恒定为10,offset为已经已经翻过的电影数量( ( 当前页数 − 1 ) ∗ 10 (当前页数-1)*10 (当前页数1)10
  • 根据响应内容可以发现所需数据皆在其中

实现

基础配置
python">import logging

logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s %(levelname)s: %(message)s')

INDEX_URL = "https://spa1.scrape.center/api/movie/?limit={limit}&offset={offset}"
爬取页面内容(获取页面的JSON内容)
python">import requests

def scrape_api(url):
    logging.info(f"scraping {url}...")
    try:
        response = requests.get(url)

        if response.status_code == 200:
            return response.json()
        logging.error(
            f"Status code: {response.status_code} while scraping {url}")
    except requests.RequestException:
        logging.error(f"Error while scraping {url}", exc_info=True)
爬取列表页(爬取指定列表页)
python">LIMIT = 10

def scrape_index(page):
    url = INDEX_URL.format(limit=LIMIT, offset=LIMIT * (page - 1))
    return scrape_api(url)

合并

python">import logging
import requests

logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s %(levelname)s: %(message)s')

INDEX_URL = "https://spa1.scrape.center/api/movie/?limit={limit}&offset={offset}"
LIMIT = 10


def scrape_api(url):
    logging.info(f"scraping {url}...")
    try:
        response = requests.get(url)

        if response.status_code == 200:
            return response.json()
        logging.error(
            f"Status code: {response.status_code} while scraping {url}")
    except requests.RequestException:
        logging.error(f"Error while scraping {url}", exc_info=True)


def scrape_index(page):
    url = INDEX_URL.format(limit=LIMIT, offset=LIMIT * (page - 1))
    return scrape_api(url)

3.4 爬取详情页

分析

  • url:最后的一个参数为此电影的id
  • 电影的id:Ajax请求返回的数据中含有电影对应的id

实现

爬取详情页
python">DETAIL_URL = "https://spa1.scrape.center/api/movie/{id}"


def scrape_detail(id):
    url = DETAIL_URL.format(id=id)
    return scrape_api(url)
串联调用
python">TOTAL_PAGE = 10


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(f"detail data {detail_data}")
            

if __name__ == "__main__":
    main()

合并

python">import logging
import requests

logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s %(levelname)s: %(message)s')

INDEX_URL = "https://spa1.scrape.center/api/movie/?limit={limit}&offset={offset}"
DETAIL_URL = "https://spa1.scrape.center/api/movie/{id}"
LIMIT = 10
TOTAL_PAGE = 10


def scrape_api(url):
    logging.info(f"scraping {url}...")
    try:
        response = requests.get(url)
        if response.status_code == 200:
            return response.json()
        logging.error(
            f"Status code: {response.status_code} while scraping {url}")
    except requests.RequestException:
        logging.error(f"Error while scraping {url}", exc_info=True)


def scrape_index(page):
    url = INDEX_URL.format(limit=LIMIT, offset=LIMIT * (page - 1))
    return scrape_api(url)


def scrape_detail(id):
    url = DETAIL_URL.format(id=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(f"detail data {detail_data}")


if __name__ == "__main__":
    main()

3.5 保存数据(MongoDB)(后期补充)


http://www.niftyadmin.cn/n/5231145.html

相关文章

PyTorch2.0环境搭建

一、安装python并配置环境变量 1、打开python官网,下载并安装 Welcome to Python.org 下载 寻找版本:推荐使用3.9版本,或其他表中显示为安全(security)的版本 安装:(略) 2、配置环…

mysql 查询提取json 并去除双引号

1.建表语句 CREATE TABLE uset_test_demo (id bigint(20) NOT NULL AUTO_INCREMENT,context text,PRIMARY KEY (id) ) ENGINEInnoDB AUTO_INCREMENT4 DEFAULT CHARSETutf8;2.源数据 {"title": "Harry Potter","author": "J.K. Rowling&qu…

一、服务器准备

本案例使用VMware Workstation Pro虚拟机创建虚拟服务器来搭建Linux服务器集群,所用软件及版本如下: Centos7.7-64bit 1、三台虚拟机创建 第一种方式:通过iso镜像文件来进行安装(不推荐) 第二种方式:直接复制安装好的虚拟机文…

mongoDB非关系型数据库学习记录

一、简介 1.1Mongodb是什么 MongoDB是一个基于分布式文件存储的数据库,官方地址https://www.mongodb.com/ 1.2数据库是什么 数据库(DataBase)是按照数据结构来组织、存储和管理数据的应用程序 1.3数据库的作用 数据库的主要作用就是管理数据,对数据进行增©、删(d)、…

如何下载IEEE出版社的Journal/Conference/Magazine的LaTeX/Word模板

当你准备撰写一篇学术论文或会议论文时,使用IEEE(电气和电子工程师协会)的LaTeX或Word模板是一种非常有效的方式,它可以帮助你确保你的文稿符合IEEE出版的要求。无论你是一名研究生生或一名资深学者,本教程将向你介绍如…

【Android面试|华为|广播类】-Local Broaddcasts 能接收到系统广播么?

华为面试官问了其中一个问题 Q: Local Broaddcasts 能接收到系统广播么? A: 本地广播(Local Broaddcasts) 只在本App发送和接收的广播。注册为本地广播的接收器无法收到标准广播。 Android应用可以通过广播从系统或其他App接收或发送消息。类…

CentOS系统环境搭建(二十四)——借助Git实现一键部署

centos系统环境搭建专栏🔗点击跳转 文章目录 如何一键部署1.后端1.1 拉取代码1.2 打包1.2.1 如果打包没问题,只看这部分即可1.2.2 maven有问题看这一部分1.2.2.1 安装jdk1.2.2.2 Jdk路径寻找,使用命令1.2.2.3 由此可知,jdk路径为…

API成批分配漏洞介绍与解决方案

一、API成批分配漏洞介绍 批量分配:在API的业务对象或数据结构中,通常存在多个属性,攻击者通过篡改属性值的方式,达到攻击目的。比如通过设置user.is_admin和user.is_manager的值提升用户权限等级;假设某API的默认接口…