天天看點

爬取微網誌評論内容

繼上次知乎話題

擁有一副好身材是怎樣的體驗?

解析了知乎回答内容之後,這次我們來解析一下微網誌内容,以微網誌網友發起的大賽為例: https://m.weibo.cn/detail/4367970740108457 https://m.weibo.cn/detail/4348022520956497

要擷取的微網誌圖檔内容,共計672張很兇的照片。

下面是講如何擷取的,不感興趣的話直接去背景回複 套圖 即可獲得。

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

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

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

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

然後後面抱着僥幸心理把通路形式改成手機,微網誌域名就從

weibo.com

變成了

weibo.cn

,再看一下 network 頁籤以hotflow 開頭的 xhr :

這時候 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 屬性,要以這種方式過濾掉。

另外還有這個:

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

值得注意的是二級評論裡不管有沒有圖檔都不會有 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字元串命名防止重複圖檔           

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

有興趣的可以回複 套圖 獲得這次微網誌圖檔和上次知乎圖檔

本次微網誌結構比較簡單,與上次關于知乎的文章差不多,不再提供源碼。