爬蟲實例——爬取淘女郎的相冊(借助谷歌瀏覽器的開發者工具找出規律快速爬取)


用正常的方式(selenium、PhantomJS、BeautifulSoup)爬取淘女郎相冊不僅困難,效率很低,而且很容易卡死。

我借助谷歌瀏覽器的開發者工具找出每個頁面的規律,快速獲取每張照片的鏈接,再下載,這樣效率就很高了。

過程

首頁很簡單,沒有采用JS渲染,直接用requests就能獲取完整的源代碼,沒什么說的。

淘女郎首頁采用了JS渲染,直接用requests是獲取不到完整的源代碼的,此時可以打開谷歌瀏覽器的開發者工具,主要看“Network”,篩選出“XHR”,如下圖:

從上圖可知,從這個頁面可以獲取淘女郎的個人資料,讀者可以直接從瀏覽器中打開該鏈接,看看是否能獲取淘女郎的個人資料。

https://mm.taobao.com/self/info/model_info_show.htm?user_id=687471686

觀察這個URL很容易發現,我們只需改變用戶ID就可以得到不同淘女郎的個人資料了,所以在爬取首頁時記得把用戶ID也爬取下來。

接下來看一下相冊,打開淘女郎的相冊,同樣是打開谷歌瀏覽器的開發者工具,看“XHR”,你可以得到這么一個鏈接:

https://mm.taobao.com/self/album/open_album_list.htm?_charset=utf-8&user_id%20=687471686

從這個鏈接你可以獲取淘女郎的相冊鏈接、名稱和照片數,但得到的只是第一頁的數據,怎么看第二頁的呢,在前台翻頁后從開發者工具可以看到多了一個XHR:

https://mm.taobao.com/self/album/open_album_list.htm?_charset=utf-8&user_id%20=687471686&page=2

這就是相冊的規律,通過兩個參數控制,一個是用戶ID,一個是頁數。

接下來看看相冊里面的內容,此時看XHR得不到我們要的內容,應該看看別的,我在JS里發現了這個頁面:

從上圖可知,這個頁面會返回JSON數據,里面包含了圖片的鏈接,但通過查找發現只有16張照片,實際上這個相冊卻有45張照片,回到前台,下拉滾動條,發現多了幾個這樣的頁面:

它們的URL分別是:

https://mm.taobao.com/album/json/get_album_photo_list.htm?user_id=687471686&album_id=10000702574&top_pic_id=0&cover=%2F%2Fimg.alicdn.com%2Fimgextra%2Fi2%2F687471686%2FTB1TlwDLFXXXXbxaXXXXXXXXXXX_!!2-tstar.png&page=1&_ksTS=1465185952899_155&callback=jsonp156

https://mm.taobao.com/album/json/get_album_photo_list.htm?user_id=687471686&album_id=10000702574&top_pic_id=0&cover=%2F%2Fimg.alicdn.com%2Fimgextra%2Fi2%2F687471686%2FTB1TlwDLFXXXXbxaXXXXXXXXXXX_!!2-tstar.png&page=2&_ksTS=1465186271282_254&callback=jsonp255

https://mm.taobao.com/album/json/get_album_photo_list.htm?user_id=687471686&album_id=10000702574&top_pic_id=0&cover=%2F%2Fimg.alicdn.com%2Fimgextra%2Fi2%2F687471686%2FTB1TlwDLFXXXXbxaXXXXXXXXXXX_!!2-tstar.png&page=3&_ksTS=1465186273660_330&callback=jsonp331

每個URL包含的參數都很多,有兩個參數(_ksTS和callback)看不出規律,於是我打開了另一個相冊,發現每個相冊的這兩個參數都是固定的,第一頁的都是155-156,第二頁的都是254-255,第三頁的都是330-331,且從第二頁開始,下一頁的callback減去上一頁的callback都等於76。

然而知道這些規律后我發現並沒什么卵用,因為我發現即使沒有這些參數也能獲取數據:

https://mm.taobao.com/album/json/get_album_photo_list.htm?user_id=687471686&album_id=10000702574&page=1

https://mm.taobao.com/album/json/get_album_photo_list.htm?user_id=687471686&album_id=10000702574&page=2

https://mm.taobao.com/album/json/get_album_photo_list.htm?user_id=687471686&album_id=10000702574&page=3

其實只需用戶ID、相冊ID和頁數即可。

接下來就是獲取每張照片的URL和保存照片了。

代碼

# -*- coding: utf-8 -*-
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
'''
作者:昨夜星辰
注意事項:該腳本只能在Linux環境用Python 2.x運行,如需在其他環境運行請讀者自行修改。
'''
import re
import os
import shutil
import requests
from bs4 import BeautifulSoup

# 創建文件夾,若已存在則刪除,再創建。
def create_folder(path):
    if os.path.exists(path):
        if os.path.isdir(path):
            shutil.rmtree(path)
        else:
            os.remove(path)
    os.mkdir(path)    
    
# 詢問用戶
def ask_user(string):
    while True:
        answer = raw_input(string)
        if answer == 'Y':
            return True
        elif answer == 'N':
            return False
        else:
            print '輸入有誤,請重新輸入!'

# 創建根目錄            
root_folder = '淘女郎'
create_folder(root_folder)

# 遍歷每位淘女郎
url = 'https://mm.taobao.com/json/request_top_list.htm?page=1'
bs1 = BeautifulSoup(requests.get(url).text, 'lxml')
for top in bs1('p', 'top'):
    name = top.find('a').text
    age = top.find('em').text
    city = top.find('span').text
    user_id = top.find('span', 'friend-follow J_FriendFollow')['data-userid']
    print '發現一位美眉,她叫做%s,今年%s,住在%s,現在開始爬取她的個人頁面……' % (name, age, city)
    
    # 以淘女郎的昵稱新建文件夾
    mm_folder = '%s/%s' % (root_folder, name)
    create_folder(mm_folder)    
    
    # 獲取淘女郎的個人資料並保存到文件
    url = 'https://mm.taobao.com/self/info/model_info_show.htm?user_id=' + user_id
    bs2 = BeautifulSoup(requests.get(url).text, 'lxml')
    base_info = bs2.find('ul', 'mm-p-info-cell clearfix')
    info_list = base_info('span')
    result = []
    result.append('昵稱:' + info_list[0].text)
    result.append('生日:' + info_list[1].text.strip())
    result.append('所在城市:' + info_list[2].text)
    result.append('職業:' + info_list[3].text)
    result.append('血型:' + info_list[4].text)
    result.append('學校/專業:' + info_list[5].text)
    result.append('風格:' + info_list[6].text)
    result.append('身高:' + base_info.find('li', 'mm-p-small-cell mm-p-height').find('p').text)
    result.append('體重:' + base_info.find('li', 'mm-p-small-cell mm-p-weight').find('p').text)
    result.append('三圍:' + base_info.find('li', 'mm-p-small-cell mm-p-size').find('p').text)
    result.append('罩杯:' + base_info.find('li', 'mm-p-small-cell mm-p-bar').find('p').text)
    result.append('鞋碼:' + base_info.find('li', 'mm-p-small-cell mm-p-shose').find('p').text)
    print '資料收集完畢,正在保存她的個人資料……',
    filename = '%s/%s.txt' % (mm_folder, name)
    with open(filename, 'w') as f:
        f.write('\r\n'.join(result))
    print '保存完畢!'
    
    # 獲取相冊的總頁數
    url = 'https://mm.taobao.com/self/album/open_album_list.htm?_charset=utf-8&user_id%20=' + user_id
    bs3 = BeautifulSoup(requests.get(url).text, 'lxml')
    album_total_page = int(bs3.find('input', id='J_Totalpage')['value'])
    
    # 遍歷每一頁
    for album_page in range(1, album_total_page + 1):
        url = 'https://mm.taobao.com/self/album/open_album_list.htm?_charset=utf-8&user_id%%20=%s&page=%d' % (user_id, album_page)
        bs3 = BeautifulSoup(requests.get(url).text, 'lxml')
        album_count = 1
        
        # 遍歷每一個相冊
        for album_area in bs3('div', 'mm-photo-cell-middle'):
            # 獲取相冊的鏈接、id、名稱和照片數
            album_url = 'https:' + album_area.find('h4').find('a')['href']
            album_id = re.search(r'album_id=(\d+)', album_url).group(1)
            album_name = album_area.find('h4').find('a').text.strip()
            pic_num = album_area.find('span', 'mm-pic-number').text
            pic_num = re.search(r'\d+', pic_num).group(0)
            print '現在開始爬取她的第%d個相冊,相冊名為:《%s》(%s張)……' % (album_count, album_name, pic_num)
            
            # 根據照片數計算總頁數
            total_page = int(pic_num) / 16 + 1            
            
            # 以相冊名新建文件夾
            album_folder = '%s/%s' % (mm_folder, album_name)
            create_folder(album_folder)
            
            pic_count = 1
            # 遍歷每一頁
            for page in range(1, total_page + 1):
                url = 'https://mm.taobao.com/album/json/get_album_photo_list.htm?user_id=%s&album_id=%s&page=%s' % (user_id, album_id, page)
                json = requests.get(url).json()
                for pic in json['picList']:
                    print '現在開始下載該相冊的第%d張照片……' % pic_count,
                    pic_url = 'https:' + pic['picUrl']
                    pic_url = re.sub(r'290', '620', pic_url)
                    filename = '%s/%s.jpg' % (album_folder, pic_count)
                    with open(filename, 'wb') as f:
                        f.write(requests.get(pic_url).content)
                    print '下載完畢!'
                    pic_count += 1
            if ask_user('該相冊已經下載完畢,是否下載下一個相冊?(Y/N)') == False:
                break
            album_count += 1
        if ask_user('當前頁的相冊已經下載完畢,是否下載下一頁?(Y/N)') == False:
            break

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM