[Python3爬蟲]Ajax請求信息的爬取

動態(tài)加載頁面信息的提取

當(dāng)我們?yōu)g覽一個新聞類的網(wǎng)站,例如微博纳击,今日頭條续扔,知乎等,由于它的內(nèi)容極多焕数,當(dāng)我們搜索某一關(guān)鍵詞的信息后纱昧,服務(wù)器只會向我們返回少量的數(shù)據(jù),微博和頭條是返回指定數(shù)量的數(shù)據(jù)堡赔,當(dāng)我們再次向下刷新的時候识脆,會再次通過Ajax請求返回指定數(shù)目的數(shù)據(jù)(如果你的網(wǎng)絡(luò)不好時,會出現(xiàn)一個表示正在加載的小圓圈的動畫效果)善已。知乎是當(dāng)瀏覽器的滾動條觸底時存璃,再次提取數(shù)據(jù)。這就產(chǎn)生了一個問題雕拼,通過爬蟲如何來提取通過Ajax請求動態(tài)加載的數(shù)據(jù)呢纵东?

模擬Ajax請求

這時需要通過Chrome等瀏覽器的開發(fā)者工具,利用Chrome開發(fā)者工具的篩選功能篩選出所有的Ajax請求啥寇。選擇network選項偎球,直接點擊XHR分析網(wǎng)頁后臺向接口發(fā)送的Ajax請求,用requests來模擬Ajax請求辑甜,那么就可以成功抓取信息了

待爬取網(wǎng)站的Ajax請求的分析

這里選擇今日頭條來搞事情衰絮,通過爬蟲來下載頭條上街拍關(guān)鍵詞的圖片,搜索關(guān)鍵詞街拍磷醋,分析Ajax請求猫牡。下面是提取到的Ajax的主要信息

Request URL: https://www.toutiao.com/search_content/?
offset=0&
format=json&
keyword=%E8%A1%97%E6%8B%8D&
autoload=true&
count=20&
cur_tab=1&
from=search_tab
1.分析請求

https://www.toutiao.com/search_content/ 這個是請求的鏈接,后面還帶了一個 ? 號邓线,之后的都是請求所帶的參數(shù)

pic1.PNG

通過刷新新內(nèi)容不斷的發(fā)送Ajax請求淌友,對比不同的幾個ajax請求煌恢,對比他們的不變的地方和改變的地方,為寫程序做好準(zhǔn)備震庭。

  • 可以發(fā)現(xiàn)每加載一次內(nèi)容參數(shù)offset加20瑰抵,表示偏移量,每次取20條數(shù)據(jù)

  • format是不變的器联,表示格式是json格式的二汛,

  • Keyword是我們搜索的關(guān)鍵字
    %E8%A1%97%E6%8B%8D& ,,可能是中文的某種加密方式加密后的結(jié)果

  • 發(fā)現(xiàn)offset加20就可以了拨拓,其他參數(shù)照搬肴颊,因為都是不變的參數(shù)

2.分析響應(yīng)
pic2.PNG

點擊Preview分析響應(yīng)內(nèi)容。我們要下載圖片渣磷,發(fā)現(xiàn)圖片鏈接都在image_list里苫昌,一篇文章的一張或多張圖片都在里面,而外層是data屬性幸海,標(biāo)題在title屬性里,這里獲取標(biāo)題名作為文件夾名稱進行存儲

代碼實現(xiàn)

  • 首先奥务,實現(xiàn)方法get_page()來加載單個Ajax請求的結(jié)果物独。其中唯一變化的參數(shù)就是offset,所以我們將它當(dāng)作參數(shù)傳遞氯葬,代碼實現(xiàn)如下:
import requests
from urllib.parse import urlencode  #Python內(nèi)置的HTTP請求庫

def get_page(offset):
    params = {
        'offset':offset,
        'format': 'json',
        'keyword':'街拍',
        'autoload':'true',
        'count':'20',
        'cur_tab':'1',
        'from' : 'search_tab',
    }
    url = 'https://www.toutiao.com/search_content/?'+ urlencode(params)  #拼接URL
    try:
        r = requests.get(url)
        if r.status_code == 200:
            return r.json()  # 返回json格式的響應(yīng)內(nèi)容
    except:
        return None
  • urllib庫

Python內(nèi)置的HTTP請求庫挡篓,通常我們使用的是功能更為強大的requests庫,用到urllib的parse工具模塊帚称,提供了許多URL處理方法官研,比如拆分、解析闯睹、合并等戏羽。用urlencode()方法構(gòu)造請求的GET參數(shù)。

  • 接下來楼吃,再實現(xiàn)一個解析方法:提取每條數(shù)據(jù)的image_list字段中的每一張圖片鏈接始花,將圖片鏈接和圖片所屬的標(biāo)題一并返回,同時構(gòu)造一個生成器孩锡。實現(xiàn)代碼如下:
def get_images(jsondata):
if jsondata.get('data'):
    for item in jsondata.get('data'):
        title = item.get('title')
        images = item.get('image_list')
        for image in images:
            yield {
                'image' : image.get('url'),
                'title' : title
            }
  • 接下來酷宵,實現(xiàn)一個保存圖片的方法save_image(),其中item就是前面get_images()方法返回的一個字典躬窜。在該方法中浇垦,首先根據(jù)item的title來創(chuàng)建文件夾,然后請求這個圖片鏈接荣挨,獲取圖片的二進制數(shù)據(jù)男韧,以二進制的形式寫入文件朴摊。圖片的名稱可以使用其內(nèi)容的MD5值,這樣可以去除重復(fù)煌抒。
def save_image(item):
if not os.path.exists(item.get('title')):
    os.mkdir(item.get('title'))
try:
    image_url = item.get('image')
    print(image_url)
    r = requests.get('http:'+image_url)
    if r.status_code == 200:
        file_path = '{0}/{1}.{2}'.format(item.get('title'),md5(r.content).hexdigest(),'jpg')
        if not os.path.exists(file_path):
            with open(file_path,'wb') as f:
                f.write(r.content)
        else:
            print('Already Downloaded', file_path)
except:
    print('Faild to Save Image')

最后仍劈,構(gòu)造一個offset數(shù)組,遍歷offset寡壮,提取圖片鏈接贩疙,并將其下載:

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

num_start = 1
num_end = 20

if __name__ == '__main__':
    pool = Pool()
    num = ([x * 20 for x in range(num_start,num_end + 1)])
    pool.map(main,num)
    pool.close()
    pool.join()
  • 整體代碼
import requests
from urllib.parse import urlencode
import os
from hashlib import md5
from multiprocessing.pool import Pool

def get_page(offset):
    params = {
        'offset':offset,
        'format': 'json',
        'keyword':'街拍',
        'autoload':'true',
        'count':'20',
        'cur_tab':'1',
        'from' : 'search_tab',
    }
    url = 'https://www.toutiao.com/search_content/?'+ urlencode(params)
    try:
        r = requests.get(url)
        if r.status_code == 200:
            return r.json()
    except:
        return None

def get_images(jsondata):
    if jsondata.get('data'):
        for item in jsondata.get('data'):
            title = item.get('title')
            images = item.get('image_list')
            for image in images:
                yield {
                    'image' : image.get('url'),
                    'title' : title
                }

def save_image(item):
    if not os.path.exists(item.get('title')):
        os.mkdir(item.get('title'))
    try:
        image_url = item.get('image')

        r = requests.get('http:'+ image_url)
        if r.status_code == 200:
            file_path = '{0}/{1}.{2}'.format(item.get('title'),md5(r.content).hexdigest(),'jpg')
            if not os.path.exists(file_path):
                with open(file_path,'wb') as f:
                    f.write(r.content)
            else:
                print('Already Downloaded', file_path)
    except:
        print('Faild to Save Image')

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

num_start = 1
num_end = 20
    
    
if __name__ == '__main__':
    pool = Pool()
    num = ([x * 20 for x in range(num_start,num_end + 1)])
    pool.map(main,num)
    pool.close()
    pool.join()

這里定義了分頁的起始頁數(shù)和終止頁數(shù),分別為num_start和num_end况既,還利用了多線程的線程池这溅,調(diào)用其map()方法實現(xiàn)多線程下載

運行效果

pic3.PNG

關(guān)于作者

個人博客:https://Yhchdev.github.io

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市棒仍,隨后出現(xiàn)的幾起案子悲靴,更是在濱河造成了極大的恐慌,老刑警劉巖莫其,帶你破解...
    沈念sama閱讀 211,290評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件癞尚,死亡現(xiàn)場離奇詭異,居然都是意外死亡乱陡,警方通過查閱死者的電腦和手機浇揩,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,107評論 2 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來憨颠,“玉大人胳徽,你說我怎么就攤上這事∷” “怎么了养盗?”我有些...
    開封第一講書人閱讀 156,872評論 0 347
  • 文/不壞的土叔 我叫張陵,是天一觀的道長适篙。 經(jīng)常有香客問我往核,道長,這世上最難降的妖魔是什么嚷节? 我笑而不...
    開封第一講書人閱讀 56,415評論 1 283
  • 正文 為了忘掉前任铆铆,我火速辦了婚禮,結(jié)果婚禮上丹喻,老公的妹妹穿的比我還像新娘薄货。我一直安慰自己,他們只是感情好碍论,可當(dāng)我...
    茶點故事閱讀 65,453評論 6 385
  • 文/花漫 我一把揭開白布谅猾。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪税娜。 梳的紋絲不亂的頭發(fā)上坐搔,一...
    開封第一講書人閱讀 49,784評論 1 290
  • 那天,我揣著相機與錄音敬矩,去河邊找鬼概行。 笑死,一個胖子當(dāng)著我的面吹牛弧岳,可吹牛的內(nèi)容都是我干的凳忙。 我是一名探鬼主播,決...
    沈念sama閱讀 38,927評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼禽炬,長吁一口氣:“原來是場噩夢啊……” “哼涧卵!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起腹尖,我...
    開封第一講書人閱讀 37,691評論 0 266
  • 序言:老撾萬榮一對情侶失蹤柳恐,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后热幔,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體乐设,經(jīng)...
    沈念sama閱讀 44,137評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,472評論 2 326
  • 正文 我和宋清朗相戀三年绎巨,在試婚紗的時候發(fā)現(xiàn)自己被綠了近尚。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 38,622評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡认烁,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出介汹,到底是詐尸還是另有隱情却嗡,我是刑警寧澤,帶...
    沈念sama閱讀 34,289評論 4 329
  • 正文 年R本政府宣布嘹承,位于F島的核電站窗价,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏叹卷。R本人自食惡果不足惜撼港,卻給世界環(huán)境...
    茶點故事閱讀 39,887評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望骤竹。 院中可真熱鬧帝牡,春花似錦、人聲如沸蒙揣。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,741評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至罩息,卻和暖如春嗤详,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背瓷炮。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工葱色, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人娘香。 一個月前我還...
    沈念sama閱讀 46,316評論 2 360
  • 正文 我出身青樓苍狰,卻偏偏與公主長得像,于是被迫代替她去往敵國和親茅主。 傳聞我的和親對象是個殘疾皇子舞痰,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,490評論 2 348

推薦閱讀更多精彩內(nèi)容

  • 第一部分 HTML&CSS整理答案 1. 什么是HTML5? 答:HTML5是最新的HTML標(biāo)準(zhǔn)诀姚。 注意:講述HT...
    kismetajun閱讀 27,449評論 1 45
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,756評論 25 707
  • 今天看到一句話响牛,特別應(yīng)景,激起了心底的些許漣漪赫段。 “夜深人靜呀打,獨坐觀心,使之妄窮而真獨露糯笙,每于此中得大機趣贬丛;既覺真...
    沐子老妖閱讀 1,109評論 0 1
  • 看到只是別人的人,總是心里感到非常的不舒服给涕。違反了自己關(guān)于人性啊豺憔,道德啊,平等啊之類的認識够庙。 不太喜歡那種太以自我...
    熱情下午閱讀 262評論 0 0
  • 夜間出行的動物有很多耘眨,人是比較明目張膽的一種昼榛。 凌晨在酒吧或是燒烤檔喝酒猜拳的人,擱在幾年前...
    南苝閱讀 172評論 0 0