芝麻HTTP:Ajax結果提取

以微博爲例,接下來用Python來模擬這些Ajax請求,把我發過的微博爬取下來。git

1. 分析請求

打開Ajax的XHR過濾器,而後一直滑動頁面以加載新的微博內容。能夠看到,會不斷有Ajax請求發出。github

選定其中一個請求,分析它的參數信息。點擊該請求,進入詳情頁面,如圖6-11所示。數據庫

圖6-11 詳情頁面json

能夠發現,這是一個GET類型的請求,請求連接爲[https://m.weibo.cn/api/container/getIndex?type=uid&value=2830678474&containerid=1076032830678474&page=2)。請求的參數有4個:typevaluecontaineridpageapi

隨後再看看其餘請求,能夠發現,它們的typevaluecontainerid始終如一。type始終爲uidvalue的值就是頁面連接中的數字,其實這就是用戶的id。另外,還有containerid。能夠發現,它就是107603加上用戶id。改變的值就是page,很明顯這個參數是用來控制分頁的,page=1表明第一頁,page=2表明第二頁,以此類推。瀏覽器

2. 分析響應

隨後,觀察這個請求的響應內容,如圖6-12所示。ide

圖6-12 響應內容工具

這個內容是JSON格式的,瀏覽器開發者工具自動作了解析以方便咱們查看。能夠看到,最關鍵的兩部分信息就是cardlistInfocards:前者包含一個比較重要的信息total,觀察後能夠發現,它實際上是微博的總數量,咱們能夠根據這個數字來估算分頁數;後者則是一個列表,它包含10個元素,展開其中一個看一下,如圖6-13所示。post

圖6-13 列表內容ui

能夠發現,這個元素有一個比較重要的字段mblog。展開它,能夠發現它包含的正是微博的一些信息,好比attitudes_count(贊數目)、comments_count(評論數目)、reposts_count(轉發數目)、created_at(發佈時間)、text(微博正文)等,並且它們都是一些格式化的內容。

這樣咱們請求一個接口,就能夠獲得10條微博,並且請求時只須要改變page參數便可。

這樣的話,咱們只須要簡單作一個循環,就能夠獲取全部微博了。

3. 實戰演練

這裏咱們用程序模擬這些Ajax請求,將個人前10頁微博所有爬取下來。

首先,定義一個方法來獲取每次請求的結果。在請求時,page是一個可變參數,因此咱們將它做爲方法的參數傳遞進來,相關代碼以下:

from urllib.parse import urlencode
import requests
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)

首先,這裏定義了base_url來表示請求的URL的前半部分。接下來,構造參數字典,其中typevaluecontainerid是固定參數,page是可變參數。接下來,調用urlencode()方法將參數轉化爲URL的GET請求參數,即相似於type=uid&value=2830678474&containerid=1076032830678474&page=2這樣的形式。隨後,base_url與參數拼合造成一個新的URL。接着,咱們用requests請求這個連接,加入headers參數。而後判斷響應的狀態碼,若是是200,則直接調用json()方法將內容解析爲JSON返回,不然不返回任何信息。若是出現異常,則捕獲並輸出其異常信息。

隨後,咱們須要定義一個解析方法,用來從結果中提取想要的信息,好比此次想保存微博的id、正文、贊數、評論數和轉發數這幾個內容,那麼能夠先遍歷cards,而後獲取mblog中的各個信息,賦值爲一個新的字典返回便可:

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)

另外,咱們還能夠加一個方法將結果保存到MongoDB數據庫:

from pymongo import MongoClient

client = MongoClient()
db = client['weibo']
collection = db['weibo']

def save_to_mongo(result):
    if collection.insert(result):
        print('Saved to Mongo')

這樣全部功能就實現完成了。運行程序後,樣例輸出結果以下:

{'id': '4134879836735238', 'text': '驚不驚喜,刺不刺激,意不意外,感不感動', 'attitudes': 3, 'comments': 1, 'reposts': 0}
Saved to Mongo
{'id': '4143853554221385', 'text': '曾經夢想仗劍走天涯,後來過安檢給收走了。分享單曲 遠走高飛', 'attitudes': 5, 'comments': 1, 'reposts': 0}
Saved to Mongo

查看一下MongoDB,相應的數據也被保存到MongoDB,如圖6-14所示。

圖6-14 保存結果

這樣,咱們就順利經過分析Ajax並編寫爬蟲爬取下來了微博列表,最後,給出本節的代碼地址:https://github.com/Python3WebSpider/WeiboList

本節的目的是爲了演示Ajax的模擬請求過程,爬取的結果不是重點。該程序仍有不少能夠完善的地方,如頁碼的動態計算、微博查看全文等,若感興趣,能夠嘗試一下。

經過這個實例,咱們主要學會了怎樣去分析Ajax請求,怎樣用程序來模擬抓取Ajax請求。瞭解了抓取原理以後,下一節的Ajax實戰演練會更加駕輕就熟。

相關文章
相關標籤/搜索