Ajax异步数据抓取

1.简介

 1 有时候我们在用requests抓取页面的时候,得到的结果可能和在浏览器中看到的不一样,在浏览
 2 器中可以看到正常显示的页面数据,但是使用requests得到的结果并没有。这是因为requests获取的
 3 都是原始的HTML文档,而浏览器中的页面则是经过JavaScript处理数据后生成的结果,这些数据的
 4 来源有多种,可能是通过ajax加载的,可能是包含在HTML文档中的,也可能是经过JavaScript和特
 5 定算法计算后生成的。
 6 对于第一种情况,数据加载是一种异步加载方式,原始的页面最初不会包含某些数据,原始页面
 7 加载完后,会再向服务器请求某个接口获取数据,然后数据才被处理从而呈现到网页上,这其实就是
 8 发送了一个ajax请求。
 9 Web发展的趋势来看,这种形式的页面越来越多,网页的原始HTML文档不会包含任何数据,
10 数据都是通过统一加载后再呈现出来的,这样在We开发上可以做到前后端分离,而且降低服
11 务器直接渲染页面带来的压力。
12 所以如果遇到这样的页面,直接requests等库来抓取原始页面,是无法获取到有效数据的,
13 这时需要分析网页后台接口发送的jax请求,如果可以用requests来模拟Ajax请求,那么就可以
14 成功抓取了。
15 Ajax,是利用JavaScript在保证页面不被刷新、页面链接不改变的情况下与服务器交换数据并更新
16 部分网页的技术。
17 Ajax作用:
18 1.发送请求。     比如:GET、POST、DELETE等请求
19 2.解析内容。     比如:服务器返回的XML、HTML、JSON等文本
20 3.渲染网页。     比如:使用JavaScript在局部更新、删除页面数据
21 在这里我们需要使用浏览器的开发者工具分析什么是ajax请求:
22 打开Chrome,在百度搜索微博并登陆也可以选择不登陆。按F12或者鼠标右键检查(N),
23 打开开发者工具,选择Network再选择XHR,然后滑动页面到底部,会发现出来很多Type是xhr类型的请求,
24 点开其中一个进行查看,请求类型是GET,再点击Preview显示的是JSON字符串,里面包含数据,
25 点开Response这是返回给我们最原始的数据,需要执行相应的渲染方法才会显示到浏览器的页面。
26
27 获取请求连接:http://api1.t.qq.com/asyn/home.php?&time=1540886592&page=4&id=486297042606010&isrecom=0&apiType=14&apiHost=http%3A%2F%2Fapi.t.qq.com&_r=154937
28 ?问号之后是请求参数,time是时间参数,page是页数,id可变随机数字,后面的参数都是固定的。
29 点击Preview,分别点开info和talk这两个元素,里面包含了用户信息和请求内容,一共15条,
30 这样请求一个ajax接口分别对应一页和15条数据

1.实战1

"""微博首页数据抓取实战,根据ajax请求抓取微博首页数据到mongodb数据库"""
import time
import requests
from urllib.parse import urlencode
from pyquery import PyQuery
from pymongo import MongoClient
# 定义请求的URL前半部分
base_url = "https://d.weibo.com/p/aj/discover/loading?"
# 连接MongoDB数据库
client = MongoClient()
# 选择一个指定的数据库
db = client["weibo"]
# MongoDB每个数据库又包含许多集合collection,它类似于关系型数据库中的表.指定一个集合
collection = db["weibo"]
# 获取请求头信息
headers = {
    "Host": "d.weibo.com",
    "Referer": "https://d.weibo.com/623751_4",
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.81 Safari/537.36",
    "X-Requested-With": "XMLHttpRequest",
    "Cookie": "SINAGLOBAL=6864515739096.891.1548998185053; login_sid_t=2559f2c7dd7bb6887ac8cdf20d7638a4; cross_origin_proto=SSL; _s_tentry=www.baidu.com; Apache=4081118444726.1284.1549420746515; ULV=1549420746520:4:4:3:4081118444726.1284.1549420746515:1549377935756; appkey=; crossidccode=CODE-gz-1GRdhO-gmK0X-y3uIsLpXUizmHrk0b096d; ALF=1580957408; SSOLoginState=1549421409; SUB=_2A25xXjsxDeThGeBH41QV9SbPyzqIHXVSKiv5rDV8PUNbmtBeLRjnkW9NQbEvXVwxASJ0zK19HvDa8bI8wpwLEiKj; SUBP=0033WrSXqPxfM725Ws9jqgMF55529P9D9W5_J5gZ9_ArKvxLE7cIcqAI5JpX5KzhUgL.Foq41hqXSKn0ehq2dJLoIpQ_BEH81F-RBC-RebXLxK-LBK-L12qN1KqES5tt; SUHB=0JvwbnCYpHgJl1; UOR=,,login.sina.com.cn; wvr=6; YF-Page-G0=0f25bf37128de43a8f69dd8388468211; wb_view_log_6986458306=1536*8641.25"
}

def get_page(page, time):
    # 构造参数字典并发起请求
    params = {
        "ajwvr": "6",
        "id": "623751_4",
        "uid": "6986458306",
        "page": page,
        "__rnd": time
    }
    # 调用urlencode()方法把参数转换为URL的GET请求参数
    url = base_url + urlencode(params)
    try:
        # 传递url和请求头信息请求网页内容
        response = requests.get(url, headers=headers)
        # 判断响应的状态码
        if response.status_code == 200:
            # 返回请求的json格式数据
            return response.json()
    except requests.ConnectionError as e:
        # 出现异常则打印
        print("Error", e.args)

def parse_page(json):
    # 解析ajax返回的json字符串
    if json:
        html = json.get("data").get("html")
        # 传递html内容初始化
        pq = PyQuery(html)
        # 使用css选择器并调用items()方法生成可迭代数据
        items = pq(".text_box").items()
        for item in items:
            # 空字典要放进循环里面来,因为数据的解析是在循环里面完成,一次循环一次解析
            weibo = {}
            # 调用find()方法传入css节点选择然后调用text()进行文本处理
            weibo["title"] = item.find("div a").text()
            weibo["text"] = item.find("div").text()
            # yield生成器保存数据为一个对象,节省内存空间
            yield weibo

def save_to_mongo(result):
    # 存储到MongoDB数据库
    if collection.insert(result):
        print("Saved to Mongo")

if __name__ == "__main__":
    # 获取时间参数
    time = int(time.time() * 1000)
    # 设置需要的页数
    for page in range(1, 11):
        # 调用函数传递页数和时间参数
        json = get_page(page, time)
        # 调用解析函数传递返回的json文本完成解析
        results = parse_page(json)
        # 循环获取生成器中的数据
        for result in results:
            print(result)
            # 调用存储到mongodb的函数完成数据入库
            save_to_mongo(result)

2.实战2

"""今日头条街拍美图实战,根据ajax请求分类别多进程下载街拍美图到本地文件"""
import os
import requests
from urllib.parse import urlencode
from hashlib import md5
from multiprocessing.pool import Pool

def get_page(offset):
    # 设置url参数和获取该url请求结果
    params = {
        "aid": "24",
        "offset": offset,
        "format": "json",
        "keyword": "街拍",
        "autoload": "true",
        "count": "20",
        "cur_tab": "1",
        "from": "search_tab",
        "pd": "synthesis",
    }
    # 调用urlencode()方法拼接url
    url = "https://www.toutiao.com/api/search/content/?" + urlencode(params)
    try:
        # 发起请求并获取结果
        res = requests.get(url)
        # 请求成功返回字符串的json格式
        if res.status_code == 200:
            return res.json()
    except requests.ConnectionError as e:
        # 请求失败,打印结果
        print("连接错误", e.args)

def get_images(json):
    # 如果有获取到数据就解析
    if json.get("data"):
        for item in json.get("data"):
            # 遍历获取需要的信息
            title = item.get("title")
            images = item.get("image_list")
            for image in images:
                # 遍历已获取的多个图片
                yield {
                    # yield生成器保存数据为一个对象,节省内存空间
                    "image": image.get("url"),
                    "title": title
                }

def save_image(item):
    # 去重并保存图片
    if not os.path.exists(item.get("title")):
        # 调用os模块的exists()方法判断当前文件夹下是否没有此名称的文件
        # 调用mkdir()方法创建此文件
        os.mkdir(item.get("title"))
    try:
        # 开始请求图片的url连接
        res = requests.get(item.get("image"))
        if res.status_code == 200:
            # 请求成功之后拼接图片下载地址。图片名称为了避免重复则使用md5加密
            file_path = "{0}/{1}.{2}".format(item.get("title"), md5(res.content).hexdigest(), "jpg")
            if not os.path.exists(file_path):
                # 去除重复下载的图片并写入新图片。‘wb‘二进制形式写入
                with open(file_path, "wb") as f:
                    f.write(res.content)
            else:
                # 重复下载
                print("Already Downloaded", file_path)
    except requests.ConnectionError as e:
        print("图片获取失败")

def main(offset):
    # 调用各功能函数并传入参数即各进程任务
    json = get_page(offset)
    for item in get_images(json):
        print(item)
        save_image(item)

if __name__ == "__main__":
    pool = Pool()
    page_list = ([x * 20 for x in range(1, 21)])
    # 调用进程池中的map()方法传入main函数和可迭代的列表
    pool.map(main, page_list)
    # 关闭进程池pool,使其不在接受新的(主进程)任务
    pool.close()
    # 主进程阻塞后,让子进程继续运行完成,子进程运行完后,再把主进程全部关掉。
    pool.join()

原文地址:https://www.cnblogs.com/Guishuzhe/p/10356784.html

时间: 2024-08-29 06:05:42

Ajax异步数据抓取的相关文章

爬虫---selenium动态网页数据抓取

动态网页数据抓取 什么是AJAX: AJAX(Asynchronouse JavaScript And XML)异步JavaScript和XML.过在后台与服务器进行少量数据交换,Ajax 可以使网页实现异步更新.这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新.传统的网页(不使用Ajax)如果需要更新内容,必须重载整个网页页面.因为传统的在传输数据格式方面,使用的是XML语法.因此叫做AJAX,其实现在数据交互基本上都是使用JSON.使用AJAX加载的数据,即使使用了JS,将数

第四章爬虫进阶之动态网页数据抓取

动态网页数据抓取 什么是AJAX: AJAX(Asynchronouse JavaScript And XML)异步JavaScript和XML.过在后台与服务器进行少量数据交换,Ajax 可以使网页实现异步更新.这意味着可以在不重新加载整个网页的情况下,对网页的某部分进行更新.传统的网页(不使用Ajax)如果需要更新内容,必须重载整个网页页面.因为传统的在传输数据格式方面,使用的是XML语法.因此叫做AJAX,其实现在数据交互基本上都是使用JSON.使用AJAX加载的数据,即使使用了JS,将数

数据抓取进度条

网页版数据抓取,没有抓取进度提示,对用户不友好,因此考虑添加进度条,进度为伪进度. css代码如下 1 <style type="text/css"> 2 .demo{ 3 padding: 2em 0; 4 background: linear-gradient(to right, #2c3b4e, #4a688a, #2c3b4e); 5 } 6 .progress{ 7 height: 25px; 8 background: #262626; 9 padding: 5

大数据抓取采集框架(摘抄至http://blog.jobbole.com/46673/)

摘抄至http://blog.jobbole.com/46673/ 随着BIG DATA大数据概念逐渐升温,如何搭建一个能够采集海量数据的架构体系摆在大家眼前.如何能够做到所见即所得的无阻拦式采集.如何快速把不规则页面结构化并存储.如何满足越来越多的数据采集还要在有限时间内采集.这篇文章结合我们自身项目经验谈一下. 我们来看一下作为人是怎么获取网页数据的呢? 1.打开浏览器,输入网址url访问页面内容.2.复制页面内容的标题.作者.内容.3.存储到文本文件或者excel. 从技术角度来说整个过程

python网页数据抓取全纪录

在本文中,我将会为你展示一个基于新的异步库(aiohttp)的请求的代替品.我使用它写了一些速度的确很快的小数据抓取器,下面我将会为你演示是如何做到的.codego.net中介绍的方法如此多样的原因在于,数据"抓取"实际上包括很多问题:你不需要使用相同的工具从成千上万的页面中抓取数据,同时使一些Web工作流自动化(例如填一些表单然后取回数据). asyncio的基本概念 asyncio是在python3.4中被引进的异步IO库.你也可以通过python3.3的pypi来安装它.它相当的

ngrep环回接口数据抓取方法,使用-d lo参数

ngrep环回接口数据抓取方法,使用-d lo参数,注意顺序: ngrep -W byline -d lo port 80

利用Selenium制作python数据抓取,以及对Selenium资源介绍

当当当~第三篇博客开始啦~ 这次的话题是数据抓取.终于到了核心部分的探讨,我的心情也是非常激动啊!如果大家baidu或者google(如果可以的话)数据抓取或者data crawling,将会找到数以千计的例子.但是大多数的代码非常的冗长,并且许多代码还是抓取静态数据之后,对动态JS写成的数据却毫无办法.或者,利用HTML解析网址后,再找到JS写的数据页面来寻找到所想要的数据. 但是!不知各位是否有发现过,如果打开chrome或者safari或者各种浏览器的审查元素.网页上能看到的数据,其实都会

delphi 用idhttp做web页面数据抓取 注意事项

这里不讨论webbrowse方式了 .直接采用indy的 idhttp  Get post 可以很方便的获取网页数据. 但如果要抓取大量数据 程序稳定运行不崩溃就不那么容易了.这几年也做了不少类似工具 总结了几点 好记性不如烂笔头. 内存泄露 获取页面文本 少不了用到html解析 具体到delphi 估计采用mshtml htmltotext 方法的不少,这个方案再大数据量时就会内存溢出 导致程序崩溃,而这并不是每个程序员都知道.解决的方案:采用自己的html解析类 这里我要感谢 武稀松(csd

Phantomjs+Nodejs+Mysql数据抓取(1.数据抓取)

概要: 这篇博文主要讲一下如何使用Phantomjs进行数据抓取,这里面抓的网站是太平洋电脑网估价的内容.主要是对电脑笔记本以及他们的属性进行抓取,然后在使用nodejs进行下载图片和插入数据库操作. 先进行所有页面的内容进行抓取 var page =require('webpage').create(); var address='http://product.pconline.com.cn/server/'; var fs = require('fs'); var mypath = 'ver