【Python3網絡爬蟲開發實戰】6-Ajax數據爬取-4-分析Ajax爬取今日頭條街拍美圖

本節中,咱們以今日頭條爲例來嘗試經過分析Ajax請求來抓取網頁數據的方法。此次要抓取的目標是今日頭條的街拍美圖,抓取完成以後,將每組圖片分文件夾下載到本地並保存下來。html

1. 準備工做

在本節開始以前,請確保已經安裝好requests庫。若是沒有安裝,能夠參考第1章。git

2. 抓取分析

在抓取以前,首先要分析抓取的邏輯。打開今日頭條的首頁www.toutiao.com/,如圖6-15所示。github

圖6-15 首頁內容json

右上角有一個搜索入口,這裏嘗試抓取街拍美圖,因此輸入「街拍」二字搜索一下,結果如圖6-16所示。數組

圖6-16 搜索結果bash

這時打開開發者工具,查看全部的網絡請求。首先,打開第一個網絡請求,這個請求的URL就是當前的連接www.toutiao.com/search/?key…,打開Preview選項卡查看Response Body。若是頁面中的內容是根據第一個請求獲得的結果渲染出來的,那麼第一個請求的源代碼中必然會包含頁面結果中的文字。爲了驗證,咱們能夠嘗試搜索一下搜索結果的標題,好比「路人」二字,如圖6-17所示。微信

圖6-17 搜索結果網絡

咱們發現,網頁源代碼中並無包含這兩個字,搜索匹配結果數目爲0。所以,能夠初步判斷這些內容是由Ajax加載,而後用JavaScript渲染出來的。接下來,咱們能夠切換到XHR過濾選項卡,查看一下有沒有Ajax請求。多線程

不出所料,此處出現了一個比較常規的Ajax請求,看看它的結果是否包含了頁面中的相關數據。ide

點擊data字段展開,發現這裏有許多條數據。點擊第一條展開,能夠發現有一個title字段,它的值正好就是頁面中第一條數據的標題。再檢查一下其餘數據,也正好是一一對應的,如圖6-18所示。

圖6-18 對比結果

這就肯定了這些數據確實是由Ajax加載的。

咱們的目的是要抓取其中的美圖,這裏一組圖就對應前面data字段中的一條數據。每條數據還有一個image_detail字段,它是列表形式,這其中就包含了組圖的全部圖片列表,如圖6-19所示。

圖6-19 圖片列表信息

所以,咱們只須要將列表中的url字段提取出來並下載下來就行了。每一組圖都創建一個文件夾,文件夾的名稱就爲組圖的標題。

接下來,就能夠直接用Python來模擬這個Ajax請求,而後提取出相關美圖連接並下載。可是在這以前,咱們還須要分析一下URL的規律。

切換回Headers選項卡,觀察一下它的請求URL和Headers信息,如圖6-20所示。

圖6-20 請求信息

能夠看到,這是一個GET請求,請求URL的參數有offsetformatkeywordautoloadcountcur_tab。咱們須要找出這些參數的規律,由於這樣才能夠方便地用程序構造出來。

接下來,能夠滑動頁面,多加載一些新結果。在加載的同時能夠發現,Network中又出現了許多Ajax請求,如圖6-21所示。

圖6-21 Ajax請求

這裏觀察一下後續連接的參數,發現變化的參數只有offset,其餘參數都沒有變化,並且第二次請求的offset值爲20,第三次爲40,第四次爲60,因此能夠發現規律,這個offset值就是偏移量,進而能夠推斷出count參數就是一次性獲取的數據條數。所以,咱們能夠用offset參數來控制數據分頁。這樣一來,咱們就能夠經過接口批量獲取數據了,而後將數據解析,將圖片下載下來便可。

3. 實戰演練

咱們剛纔已經分析了一下Ajax請求的邏輯,下面就用程序來實現美圖下載吧。

首先,實現方法get_page()來加載單個Ajax請求的結果。其中惟一變化的參數就是offset,因此咱們將它看成參數傳遞,實現以下:

12345678910111213141516171819import requestsfrom urllib.parse import urlencode def get_page(offset):    params = {        'offset': offset,        'format': 'json',        'keyword': '街拍',        'autoload': 'true',        'count': '20',        'cur_tab': '1',    }    url = 'http://www.toutiao.com/search_content/?' + urlencode(params)    try:        response = requests.get(url)        if response.status_code == 200:            return response.json()    except requests.ConnectionError:        return None複製代碼

這裏咱們用urlencode()方法構造請求的GET參數,而後用requests請求這個連接,若是返回狀態碼爲200,則調用responsejson()方法將結果轉爲JSON格式,而後返回。

接下來,再實現一個解析方法:提取每條數據的image_detail字段中的每一張圖片連接,將圖片連接和圖片所屬的標題一併返回,此時能夠構造一個生成器。實現代碼以下:

def get_images(json):    if json.get('data'):        for item in json.get('data'):            title = item.get('title')            images = item.get('image_detail')            for image in images:                yield {                    'image': image.get('url'),                    'title': title                }複製代碼

接下來,實現一個保存圖片的方法save_image(),其中item就是前面get_images()方法返回的一個字典。在該方法中,首先根據itemtitle來建立文件夾,而後請求這個圖片連接,獲取圖片的二進制數據,以二進制的形式寫入文件。圖片的名稱可使用其內容的MD5值,這樣能夠去除重複。相關代碼以下:

import osfrom hashlib import md5 def save_image(item):    if not os.path.exists(item.get('title')):        os.mkdir(item.get('title'))    try:        response = requests.get(item.get('image'))        if response.status_code == 200:            file_path = '{0}/{1}.{2}'.format(item.get('title'), md5(response.content).hexdigest(), 'jpg')            if not os.path.exists(file_path):                with open(file_path, 'wb') as f:                    f.write(response.content)            else:                print('Already Downloaded', file_path)    except requests.ConnectionError:        print('Failed to Save Image')
複製代碼

最後,只須要構造一個offset數組,遍歷offset,提取圖片連接,並將其下載便可:

from multiprocessing.pool import Pool

def main(offset):
    json = get_page(offset)
    for item in get_images(json):
        print(item)
        save_image(item)


GROUP_START = 1
GROUP_END = 20

if __name__ == '__main__':
    pool = Pool()
    groups = ([x * 20 for x in range(GROUP_START, GROUP_END + 1)])
    pool.map(main, groups)
    pool.close()
    pool.join()
複製代碼

這裏定義了分頁的起始頁數和終止頁數,分別爲GROUP_STARTGROUP_END,還利用了多線程的線程池,調用其map()方法實現多線程下載。

這樣整個程序就完成了,運行以後能夠發現街拍美圖都分文件夾保存下來了,如圖6-22所示。

圖6-22 保存結果

最後,咱們給出本節的代碼地址:github.com/Python3WebS…

經過本節,咱們瞭解了Ajax分析的流程、Ajax分頁的模擬以及圖片的下載過程。

本節的內容須要熟練掌握,在後面的實戰中咱們還會用到不少次這樣的分析和抓取。


本資源首發於崔慶才的我的博客靜覓: Python3網絡爬蟲開發實戰教程 | 靜覓

如想了解更多爬蟲資訊,請關注個人我的微信公衆號:進擊的Coder

weixin.qq.com/r/5zsjOyvEZ… (二維碼自動識別)

相關文章
相關標籤/搜索