zoukankan      html  css  js  c++  java
  • 爬虫—Ajax数据爬取

    一、什么是Ajax

      有时候我们使用浏览器查看页面正常显示的数据与使用requests抓取页面得到的数据不一致,这是因为requests获取的是原始的HTML文档,而浏览器中的页面是经过JavaScript处理数据后的结果。这些数据可能是通过Ajax加载的,可能包含HTML文档中,可能经过特定算法计算后生成的。

      Ajax,全称为Asynchronous JavaScript and XML,即异步的JavaScript和XML。它是利用JavaScript在保证页面不被刷新,连接不变的情况下服务器交换数据并更新部分网页的技术。

    1.示例

      浏览网页的时候,我们发现很多网页都有下滑查看更多的选项。比如,就拿新浪微博主页来说。一直往下滑,看到几个微博之后就没有了,而是会出现一个加载的动画,很快就出现了新的微博内容。这个过程就是Ajax加载的过程,如下图:

              

    2.基本原理

      发送Ajax请求到网页更新的过程可以简单的分为三步:

      1.发送请求

      2.解析内容

      3.渲染页面

    ♦ 发送请求

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

      这是使用JavaScript对Ajax的底层实现,实际上是新建了XMLHttpRequest对象,然后调用onreadystatechange实现设置了监听,然后使用open()和send()方法向某个连接(也就是服务器)发送请求。响应返回时监听对应的方法便触发,解析响应内容。

    ♦ 解析内容

      onreadystatechange对应的属性触发后,利用xmlhttp的responseText属性获取响应内容。

    ♦渲染网页

      解析响应完成之后,通过document.getElementById("content").innerHTML这样的方法对某个元素内部的HTML代码进行更改,从而渲染网页。这样的操作也称为DOM操作,即对Document进行操作。

      因此,我们知道了真实的数据都是一次次Ajax请求得到的,如果想要抓取这些数据,需要知道这些请求到底是怎么发送的。之后再使用Python进行模拟发送操作,获取到其中的结果。

    二,Ajax方法分析

    1.查看请求

      使用Chrome浏览器访问新浪微博首页,打开开发者工具。切换到Network选项卡,重新刷新页面,看到非常多的条目。

           

      Ajax请求其实有它特殊的请求类型,叫做xhr。在途中Type对应请求类型中,点击图中的XHR可以过滤出所有的xhr请求。找到其中一个xhr的请求,点击进去查看详细内容。其中Request Headers中有一条信息为X-Requested-With:XMLHttpRequest,这就标记了次请求是Ajax请求。如下图

            

     三,Ajax结果提取

      1.请求分析

        使用开发者工具打开Ajax的XHR过滤器,然后一直向下滑动页面,我们会看到不断有Ajax请求发出。选定其中一个请求,分析其参数信息,进入请求详情。如下图:

         

      可以发现,这是一个GET请求,url为https://weibo.com/a/aj/transform/loadingmoreunlogin?                                    ajwvr=6&category=0&page=3&lefnav=0&cursor=&__rnd=1559115353265。请求的参数有六个:ajwvr,category,page,lefnav,cursor,__rnd。

      再看看其他请求,发现只有page,__rnd这两个参数在改变。很明显page是用来控制分页的,细心观察__rnd的值为对应的时间戳。

    2.分析响应

      观察这个请求的响应内容:  

           

       这个内容的格式为JSON,其中主要的内容在data对应的值里面。这样我们请求一个接口,改变page参数就可以获得对应数据。

    3.爬取数据

      这里我们来模拟这戏Ajax请求,将前10页的数据爬取下来。  

    # _*_ coding=utf-8 _*_
    
    import requests, time
    from urllib.parse import urlencode
    
    base_url = 'https://weibo.com/a/aj/transform/loadingmoreunlogin?'
    headers = {
        'Host': 'weibo.com',
        'Referer': 'https://weibo.com/',
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36',
        'X-Requested-With': 'XMLHttpRequest',
    }
    
    
    def get_page(page):
        """
        :param page:
        :return:
        """
        # 构造__rnd参数
        rnd = int(time.time())
        # 构造参数字典
        params = {
            'ajwvr': '6',
            'category': '0',
            'page': page,
            'lefnav': '0',
            'cursor': '',
            '__rnd': rnd
    
        }
        # 拼接参数与url
        url = base_url + urlencode(params)
    
        try:
            res = requests.get(url, headers=headers)
            if res.status_code == 200:
                return res.json()
        except Exception as e:
            print('Error:', e.args)
    
    
    def parse(res):
        weibo = {}
        if res:
            weibo['data'] = res.get('data')
            yield weibo
    
    
    if __name__ == "__main__":
        for page in range(1, 11):
            result = get_page(page)
            weibo_data = parse(result)
            for data in weibo_data:
                print(data)
    View Code

      运行结果:

    {'data': '    <!--榜单栏位置-->
                        <!--/ card-->
    <div class="UG_slider" >
        <ul action-type="header_slider" node-type="header_slider">
                <li>
                <a href="/a/hot/7562265474177025_1.html?type=new" target="_blank" suda-uatrack="key=www_unlogin_home&value=focus01">
                <img src="https://wx2.sinaimg.cn/crop.0.61.600.337/60718250ly1g3hxko6uxbj20go0b30t9.jpg" class="pic"><div class="pic_intro">头条新闻今日快讯 | 华为在美提起诉讼.....}

      这样我们就通过分析Ajax请求并编写爬虫获取到微博数据,当然代码还可更优化,还可以解析具体的标题、内容,这里只是演示Ajax请求的模拟过程,爬取结果并不是重点。

     
  • 相关阅读:
    [UE4]Spline
    [UE4]Spline Mesh Actor
    SpringBoot的jar包引用外部properties文件
    如何将.crt文件转换为.cer格式
    消息队列之 RabbitMQ
    The last packet successfully received from the server was 8 milliseconds ago.
    DEBUG、INFO、WARN、ERROR、CRITICAL开发日志级别定义
    灰度发布-流程篇
    k8s+istio:流量控制之灰度发布
    微服务、SpringCloud、k8s、Istio杂谈
  • 原文地址:https://www.cnblogs.com/zivli/p/10944819.html
Copyright © 2011-2022 走看看