1. 程式人生 > >圍觀微博網友發起的美胸比賽學習爬取微博評論內容

圍觀微博網友發起的美胸比賽學習爬取微博評論內容

網友:看看胸 女:滾

網友:美胸比賽 女:[圖片訊息] ​​​​

繼上次知乎話題 擁有一副好身材是怎樣的體驗? 解析了知乎回答內容之後,這次我們來解析一下微博內容,以微博網友發起的美胸大賽為例:

https://m.weibo.cn/detail/4367970740108457

https://m.weibo.cn/detail/4348022520956497

這就是本次要獲取的微博圖片內容,共計672張很凶的照片:

xiong.png

下面是講如何獲取的,不感興趣的話直接去公眾號回覆 套圖 即可獲得。


首先進入開發者工具看一下微博結構:

weibocom.png 這只是一小部分,微博評論和微博使用者發的微博頁面,裡面都是以html5格式傳到本地的,把內容格式化之後就會發現,層級非常複雜,有興趣的可以看一下,與其解析這個還不如用selenium更簡單一些。於是當時就產生了兩個思路:

  • 藉助 splash 直接解析渲染後的頁面
  • 用 mitmproxy 抓手機APP微博的包,用 APPium 控制手機重新整理評論

不管是哪一種,相對於只是獲取一下圖片而言都麻煩。於是去網上搜一下,搜尋結果都是前兩年爬取微博的方法,那時候還是用 ajax 以 json 格式傳遞,現在明顯已經不是。

然後後面抱著僥倖心理把訪問形式改成手機,微博域名就從 weibo.com 變成了 weibo.cn,再看一下 network 選項卡以hotflow 開頭的 xhr :

weibocn.png

這時候 weibo.cn 傳給本地資訊就是簡單的 json 格式啦。上圖就是微博評論列表的評論,可以看到每條評論如果有圖片,就會有 pic 屬性,但是要注意在 pic 下的 直接子 url 只是預覽圖連結,並非原圖。原圖連結在pic 屬性下 large 下的 url。其他的屬性是一些微博的標題、傳送時間、內容、點贊數、評論數、轉發數和博主相關資訊等。我們這次重點是圖片,就不管其他的了。

另外微博的反爬措施很強,真的噁心到我了,如果有大規模爬取需求,建議去淘寶買號,建 Cookie池,或者用代理池不停地切換訪問主機。如果只用自己電腦本地Cookie,那就把請求頭弄全,並限制抓取速度。

切換到 Headers 選項卡,看一下 Request URL

https://m.weibo.cn/comments/hotFlowChild?cid=4376866645060411&max_id=152030087630286&max_id_type=0

可以看出它的格式是

https://m.weibo.cn/comments/hotFlowChild? + cid + max_id + max_id_type

'

其中 cid 是每一條微博的唯一ID,max_id 是下一次傳回資料的最後一條評論的 ID。也就是往下翻看評論,每次顯示十條,並在這次所看的評論裡就傳回 下十條評論 的最後一條評論的唯一 ID,微博是根據這個 ID 傳回下十條內容。這也就直接限制了每次爬評論、微博、二級評論時只能一次獲取十條,也無法利用執行緒池加速,因為只有獲取了這十條才知道下十條請求地址裡 max_id 的值。

然後就可以由這些資訊構造請求,獲取 json 格式的響應結果:

comment_url = 'https://m.weibo.cn/comments/hotflow?id={weibo_id}&mid={weibo_id}&max_id={max_id}&max_id_type=0'
url = comment_url.format(weibo_id=id, max_id=0)
response = requests.get(url, headers=headers)
result = json.loads(response.text)

先獲取總評論數來計算需要多少次才能爬完評論:

total_number = result.get('data').get('total_number')
total_number = int(total_number)
for i in range(int(total_number / 10)):
    result = get_page(weibo_id)
    for url in parse_comment(result):
    	save_to_img(url)

下載完圖片只有700來張才知道靠後的評論都是無用的(男士跟答主要聯絡方式什麼的)評論。

然後就是獲取圖片地址:

def parse_comment(result):
    if result.get('ok') and result.get('data').get('data'):
        comments = result.get('data').get('data')
        for comment in comments:
            if comment.get('pic'):
                url = comment.get('pic').get('large').get('url')
                yield url

要先 if comment.get('pic') 一下,這很重要,因為很多無用評論並沒有配圖,也就是沒有 pic 屬性,要以這種方式過濾掉。

另外還有這個:

child_comment.png

這裡的二級評論就很有必要爬一下,看一下結構:

child_com.png

值得注意的是二級評論裡不管有沒有圖片都不會有 pic 屬性,圖片在回答內容text 裡以 css 方式巢狀的,很明顯就是 a 標籤下的 href 屬性 就是圖片地址。用 pyquery 取出來地址:

childs_comment = result.get('data')
for child_comment in childs_comment:
	text = child_comment.get('text')
	content = pyquery.PyQuery(text)
	url = content('a').attr('href')
	yield url

儲存圖片以圖片內容的 md5 值命名,可以去重:

response = requests.get(url)
if response.status_code == 200:img_path = '{0}/{1}.{2}'.format(path,md5(response.content).hexdigest(), 'jpg')  # 以圖片的md5字串命名防止重複圖片

最後接入某大廠的人體特徵值檢測,考慮到圖片大多沒有露臉,識別男女性別不夠準,這裡只把未識別出人體的圖片去掉了(一些表情圖)。

有興趣的可以公眾號回覆 套圖 獲得這次微博圖片和上次知乎圖片

本次微博結構比較簡單,與上次關於知乎的文章差不多,不再提供原始碼。

公眾號:愛寫bug(ID:iCodeBugs)