爬蟲—Ajax數據爬取

1、什麼是Ajax

  有時候咱們使用瀏覽器查看頁面正常顯示的數據與使用requests抓取頁面獲得的數據不一致,這是由於requests獲取的是原始的HTML文檔,而瀏覽器中的頁面是通過JavaScript處理數據後的結果。這些數據多是經過Ajax加載的,可能包含HTML文檔中,可能通過特定算法計算後生成的。html

  Ajax,全稱爲Asynchronous JavaScript and XML,即異步的JavaScript和XML。它是利用JavaScript在保證頁面不被刷新,鏈接不變的狀況下服務器交換數據並更新部分網頁的技術。node

1.示例

  瀏覽網頁的時候,咱們發現不少網頁都有下滑查看更多的選項。好比,就拿新浪微博主頁來講。一直往下滑,看到幾個微博以後就沒有了,而是會出現一個加載的動畫,很快就出現了新的微博內容。這個過程就是Ajax加載的過程,以下圖:ajax

          

 

2.基本原理

  發送Ajax請求到網頁更新的過程能夠簡單的分爲三步:算法

  1.發送請求json

  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()方法向某個鏈接(也就是服務器)發送請求。響應返回時監聽對應的方法便觸發,解析響應內容。ide

♦ 解析內容工具

  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': '    <!--榜單欄位置-->\n                    <!--/ card-->\r\n<div class="UG_slider" >\r\n    <ul action-type="header_slider" node-type="header_slider">\r\n            <li>\r\n            <a href="/a/hot/7562265474177025_1.html?type=new" target="_blank" suda-uatrack="key=www_unlogin_home&value=focus01">\r\n            <img src="https://wx2.sinaimg.cn/crop.0.61.600.337/60718250ly1g3hxko6uxbj20go0b30t9.jpg" class="pic"><div class="pic_intro">頭條新聞今日快訊 | 華爲在美提起訴訟.....}

  這樣咱們就經過分析Ajax請求並編寫爬蟲獲取到微博數據,固然代碼還可更優化,還能夠解析具體的標題、內容,這裏只是演示Ajax請求的模擬過程,爬取結果並非重點。

相關文章
相關標籤/搜索