python--Ajax

  • 我们在用requests抓取页面的时候,得到的结果可能和在浏览器中看到的不一样,是因为requests抓取的都是原始的HTML文档,而浏览器中的页面则是经过JavaScript处理数据后生成的结果,这些数据都来源有多种可能是通过Ajax加载的,可能是包含在HTML文档中的,也可能是经过JavaScript和特定算法计算后生成的。
  •  对于第一种情况,数据加载是一种异步加载方式,原始的页面最初不会包含某些数据,原始页面加载完成后,会再向服务器请求某个接口获取数据,然后数据才被处理从而呈现在网页上,这其实就是发送了一个Ajax请求。
  • 这样在web开发上实现前后端分离,可以降低服务器直接渲染页面带来的压力。

1. 什么是Ajax

        Ajax,(asynchronous JavaScript and XML)即异步的JavaScript and XML。他不是一门编程语言,而是利用JavaScript 在保证页面不被刷新、页面链接不改变的情况下与服务器交换数据并更新部分网页的技术。(https://www.w3school.com.cn/ajax/ajax_xmlhttprequest_send.asp

1.1实例

浏览网页的时候,会发现很多网页都有下滑查看更多的选项。我们注意到,其实页面并没有整个刷新,页面的链接没有变化。这个过程就利用了Ajax。

1.2基本原理

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

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

我们知道JavaScript可以实现页面的各种交互功能,Ajax也不例外,他也是由JS实现的,实际上执行了下面的代码:

 

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();    

 

          这是JS对Ajax最底层的实现,实际上就是新建了 XMLHttpResquest 对象,然后调用onreadystatechange 属性设置了监听,然后调用send()和 open()方法向某个链接(服务器)发送了请求。

 

        前面用Python实现请求发送之后,可以得到响应结果,但这里请求的发送变成JS来完成。由于设置了监听,所以当服务器返回响应时,onreadystatechange 对应的方法便会被触发,然后在这个方法里面解析响应内容即可。

 

  • 解析内容

得到响应之后,onreadystatechange 属性对应的方法便会被触发,此时利用   xmlhttp.responseText 便可以获取响应内容。(这类似于Python中利用resquests 向服务器发送请求,然后得到响应的过程。)返回的内容可能是 HTML,可能是JSON,接下来只需在方法中用JS 进一步处理即可。 

 

  • 渲染网页

JS有改变网页内容的能力,解析完响应内容之后,就可以调用JS 来针对解析完的内容对网页进行下一步处理了。比如:通过 document.getElementById().innerHTML  这样的操作,对某个元素内的源代码进行更改,这样网页显示的内容就改变了,这个样的操作也被称为DOM操作。

 

2. Ajax分析方法

2.1 查看请求

借助浏览器的开发者工具(Chrome为例):

打开网页——右键——检查;

             

        切换到Network选项卡:

                       这里就是网页加载郭传给你中浏览器与服务器之间发送请求和接收响应的所有记录。

 

Ajax有其特殊的请求类型——xhr.

在Type中找到一个  xhr  ,点开查看详细信息,Request Headers中有一个信息为 X-Requested-With:XMLHttpRequest, 这就标记了此请求是Ajax请求。

             

点击Preview,可看到响应的内容,它是 JSON 格式的,这里Chrome 自动做了解析。

切换到Response 选项卡,可以看到真实的返回数据。

 

2.2 过滤请求

利用Chrome开发者工具的筛选功能选出所有的Ajax请求。

   

          So far ,我们已经可以分析出Ajax请求的一些详细的信息了,通过模拟Ajax 请求,就可以抓取数据了。

2.3 Ajax结果提取

  • 分析请求

       打开Ajax的XHR过滤器,一直滑动页面发现会不断有 Ajax 请求发出。

 

           这是一个GET类型的请求,请求的参数有4个:type,value,containerid 和page ,只有page 是变化的。

  • 分析响应

 

        响应内容是JSON 格式的,浏览器开发者工具自动做了解析。由上图可以看到,最关键的两部分信息是 cardlistInfo 和 cards,前者包含一个重要的信息是total,后者是一个列表,包含8个元素。展开一个元素看看:

   mblog是这个元素比较重要的一个字段,包含微博的一些信息,发布时间吗,赞数目。。。。。。

  • 实例

获取微博的前10页,先定义url 的前半部分,因为page是变化的,构造参数字典。

//发送请求
import
requests from urllib.parse import urlencode base_url = 'https://m.weibo.cn/api/container/getIndex?' headers = { 'Host': 'm.weibo.cn', 'Referer': 'https://m.weibo.cn/u/2830678474', 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36', 'X-Requested-With': 'XMLHttpRequest', } def get_page(page): params = { 'type': 'uid', 'value': '2830678474', 'containerid': '1076032830678474', 'page': page } 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)

        发送请求之后,定义一个解析方法。从结果中提取想要的信息。

from pyquery import PyQuery as pq

def parse_page(json):
    if json:
        items = json.get('data').get('cards')
        for item in items:
            item = item.get('mblog')
            weibo = {}
            weibo['id'] = item.get('id')
            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

这里借助pyquery 将正文中的 HTML 标签去掉。

最后,遍历一下page ,一共10页,将提取到的结果打印输出即可;

if __name__ == '__main__':
    for page in range(1, 11):
        json = get_page(page)
        results = parse_page(json)
        for result in results:
            print(result)          

下一步将数据格式化存储在数据库。

 (代码参考来源:https://github.com/Python3WebSpider/WeiboList/blob/master/weibo.py

2.4 分析Ajax 爬取今日头条美图

  • 逻辑分析

首先打开今日头条的首页http://www.toutiao.com

 

 

在搜索栏输入:街拍

 

            

               可参考他人代码:https://github.com/Python3WebSpider/Jiepai

 

原文地址:https://www.cnblogs.com/bltstop/p/11660545.html