1. 程式人生 > >Talk is cheap,show me the code

Talk is cheap,show me the code

平時沒事就喜歡刷刷微博,追追星,關注關注娛樂圈動態順便看看老婆們的最新動態,每次看到老婆們發的新圖就很幸福,於是就想寫個爬蟲把老婆們的微博配圖給爬下來,一般爬到的不是自拍就是表情包,還是收穫滿滿的。
因為最近學到了一句話:不要重複造輪子。所以第一當然是去看一看有沒有別的寫出來的成品,然後發現確實有,但沒有找到特別合適的,當然每個人都有自己的要求,別人的程式碼不符合自己的需求也是正常的。不過看了這麼多程式碼,自然也就有了個大概的思路,於是經過三天兩夜的努力,就有了這篇作品,看著老婆們靜靜地躺在我的硬盤裡對我甜甜地笑著,心裡真的別提有多開心了(* ̄3 ̄)╭
思路
首先遇到的問題是去哪個頁面抓取,開始自己嘗試的時候是直接去微博網頁端:

https://www.weibo.com,然後發現…好像有點難,不知道從何下手,聽說api還限制了爬取速度,爬的賊慢,所以web端pass。接著我又去了移動端也就是html5版:https://m.weibo.cn,聽說介面也比較好,是比較好實現的,但我這條菜鳥又遇到了一個問題,因為html5版的微博頁面和web端一樣也是採用動態載入的,什麼是動態載入呢,就是你開啟一頁可以一直往下翻,他會一直幫你自動載入,直到底部。這就導致了程式碼是根據你的行為(滑鼠的點選等等)不斷變化的。所以我就選擇了更加簡單的移動版,應該是老年機版:https://weibo.cn,這裡的頁面是分頁式的,程式碼好像也是靜態的,十分輕鬆就能完成任務。
接著第二個問題是模擬登陸,開始我想著是post模擬登陸輸入使用者賬號和密碼即可,後來發現是我想多了…好像有點困難,於是就採用了cookie直接登陸,這個方法簡單粗暴,適合我這種菜雞。cookie直接在chrome按f12選擇Network點選第一個網頁,再點右邊的Headers–>Request Headers,賦值下面的cookie即可。百度可以很輕鬆的找到方法。
想清楚上面的問題後就開始分析移動端的網頁構造了,經過分析原始碼,發現微博總頁數是一個input標籤的value屬性,而input標籤的name屬性為’mp’,這是唯一的。然後每條微博的程式碼塊由div標籤閉合,含有id屬性並且class屬性的值均為’c’。微博配圖所對應的url連結由img標籤閉合,而且該標籤的alt屬性的值均為’圖片’。然後微博傳送時間的標籤為span標籤,span標籤的class屬性的值為’ct’,這也是傳送時間的程式碼塊特有的屬性值。
屁話少說,放碼過來

import requests
from bs4 import BeautifulSoup as bs
import os
import re

#uid即進入對方微博主頁後網址部分/u/後的那一串數字
uid = input('請輸入所要爬取的使用者id:')
url = 'https://weibo.cn/u/' + uid
cookie = input('請輸入你的新浪微博的cookie:')
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.108 Safari/537.36'
, 'Cookie': cookie} r = requests.get(url, headers=headers) soup = bs(r.text, 'html.parser') # 所訪問的微博使用者名稱 weibo_user_name = soup.find('title').text.replace('的微博', '') # 存放圖片的根目錄 rootDir = 'D://微博配圖相簿//' + weibo_user_name + '//' # 微博總頁數,通過審查元素可知 totalPage = int(soup.find('input', attrs={'name': 'mp'}).attrs['value']) print('總共檢測到%d頁微博頁面' % totalPage) # 每頁微博的URL的列表 weibo_urlList = [url + '?page=' + str(i + 1) for i in range(totalPage)] #當前已爬取的圖片總數 pictrue_num = 0 for page, weibo_url in enumerate(weibo_urlList): r = requests.get(weibo_url, headers=headers) soup = bs(r.text, 'html.parser') #每條微博所對應的標籤程式碼塊列表 weibo_tags_list = soup.find_all('div', attrs={'class': 'c'}, id=True) #微博傳送時間與微博配圖的字典 imgs_urls_dic = {} for entry, weibo_tag in enumerate(weibo_tags_list): print('正在爬取第%d頁第%d條微博' % (page + 1, entry + 1)) #獲取微博傳送時間 hms = ' '.join(weibo_tag.find( 'span', attrs={'class': 'ct'}).text.replace('\xa0', ' ').replace(':', '-').split(' ')[:2]) #該條微博若帶有組圖,獲取組圖中所有圖片的URL if weibo_tag.find('a', text=re.compile('組圖')): imgs_url = weibo_tag.find('a', text=re.compile('組圖')).attrs['href'] html = requests.get(imgs_url, headers=headers) imgs_soup = bs(html.text, 'html.parser') imgs_tags_List = imgs_soup.find_all('img', alt='圖片載入中...') img_urls_list = [imgs_tag.attrs['src'].replace( 'thumb180', 'large') for imgs_tag in imgs_tags_List] imgs_urls_dic[hms] = img_urls_list #該條微博僅有一張配圖,或者沒有圖片,獲取圖片的URL else: img_tags_List = weibo_tag.find_all('img', alt='圖片') img_urls_list = [img_tag.attrs['src'].replace( 'wap180', 'large') for img_tag in img_tags_List] imgs_urls_dic[hms] = img_urls_list print('第%d頁微博爬取完畢,開始生成圖片' % (page + 1)) for hms, img_urls_list in imgs_urls_dic.items(): for index, img_url in enumerate(img_urls_list): #生成圖片的存放路徑,圖片被命名為微博傳送時間 path = rootDir + hms #如果一條微博在同一時間傳送了多張圖片(即組圖)的命名處理 if(index > 0): path = path + '(' + str(index) + ')' path = path + '.jpg' try: if not os.path.exists(rootDir): #makedirs遞迴生成多級目錄,mkdir僅能生成一級目錄 os.makedirs(rootDir) if not os.path.exists(path): r = requests.get(img_url) with open(path, 'wb') as f: f.write(r.content) pictrue_num = pictrue_num + 1 print('success,成功爬取第%d張圖片' % pictrue_num) else: print('%s已經存在' % path) except: print('爬取失敗,%s' % img_url) print('總共爬取了%d張圖片,存放在 %s 目錄下' % (pictrue_num, rootDir))

食用方法
執行後輸入目標使用者id和自己的cookie就行了,執行結果是爬取目標微博的配圖並以微博傳送時間命名存放在指定目錄下。然後就可以每天欣賞女神的各種高清寫真了。經過測試,該程式碼可能會有bug爬取不下來的。但是感覺還是適用於大多數情況的。
感想
需求永遠是第一生產力,老婆才是最大的動力! ! !順便吐槽一下idle和sublime,各種bug導致執行錯誤,快要被逼瘋了! ! !