芝麻HTTP:分析Ajax爬取今日頭條街拍美圖

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

1. 準備工做

在本節開始以前,請確保已經安裝好requests庫。github

2.實戰演練 

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

import requests
from 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值,這樣能夠去除重複。相關代碼以下:ide

import os
from 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,提取圖片連接,並將其下載便可:url

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()方法實現多線程下載。spa

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

最後,咱們給出本節的代碼地址:https://github.com/Python3WebSpider/Jiepaicode

相關文章
相關標籤/搜索