記得半個月以前的一晚,媳婦跟jb說,你看,蒼老師發了條微博,內容爲69,後來微博官方關閉了該條微博的評論功能~ css
雖然不知道69是什麼意義,可是看評論,總感受是要開車了~html
打開連接:
https://weibo.com/u/1739928273?refer_flag=1001030101_&is_all=1#_rnd1530254292380
打開後就是蒼老師的微博連接,能夠看到,下面就是蒼老師發佈的微博拉,而內容就是咱們想要的東西~json
像微博這種大廠,想都不用想就知道解析html獲取數據這條路是行不通的,那咱們F12 刷新下網頁,看看請求? segmentfault
(5分鐘過去了)尼瑪,怎麼一條微博動態都沒看到,怎麼獲取?api
嘗試屢次,依然找不到解決方案,欲想放棄,此時,三三同窗說,用wap版,微博有接口獲取!!!瀏覽器
就這樣,轉戰手機版,手機版蒼老師連接以下:https://m.weibo.cn/u/1739928273;
老規矩,F12刷新網頁,而後把請求一條一條過,結果發現一個玩意:app
比起PC版,手機版終於看到有點相似數據的東西了,那咱們打開第一條看看~函數
那咱們點擊headers,把request url拿出來分析下: 優化
https://m.weibo.cn/api/container/getIndex?type=uid&value=1739928273&containerid=1076031739928273
複製代碼
解析這這個url,這url帶有3個參數:ui
type=uid
value=1739928273
containerid=1076031739928273
複製代碼
這3個參數,惟一能肯定的就是value,爲何這麼說?回頭看看蒼老師手機版的連接:https://m.weibo.cn/u/1739928273,由此得知,1739928273就是蒼老師微博的ID,不信, 你隨便改下試試,可能會跳到其餘老師那呢~
這不,簡單把最後2位73改爲12,就變成另外一位美女了~
貌似跑題了,咳咳,剛剛說到哪~
嗯,知道這幾個參數,沒啥特別的,那咱們試試滑動下屏幕,往下拉,拉取更多的數據,最後使用上面的方式,獲取url:
https://m.weibo.cn/api/container/getIndex?type=uid&value=1739928273&containerid=1076031739928273&page=3
複製代碼
與上面的url不一樣的是,這裏多了個參數page=3,不用想都知道,這是表明第三頁的意思了~
結果分析,若是是第二頁,page=2,第一頁的話,是不攜帶page參數,可是嘗試把page=0跟page=1兩個狀況,返回的數據跟不攜帶page參數是一直的,因此後面就把首頁當作是page=1的狀況處理~
ok,如今知道了數據在哪裏,翻頁怎麼弄,那咱們就看看請求頭把~
這個東西對於咱們有影響嗎?暫時看是沒有的,從上圖就能看到請求的內容跟攜帶的參數~
那咱們打開看看,下面這條連接是什麼內容?
https://m.weibo.cn/api/container/getIndex?type=uid&value=1739928273&containerid=1076031739928273
複製代碼
嗯,打開以後,是這樣的,wtf??這是什麼??
此時,趕忙看看蒼老師的內容:
這個問題,以前在寫urllib的時候也說明過:
URL只容許部分ASCLL(數字字母和部分符號),其餘的字符(包括漢字)是不符合URL的標準,
因此URL須要對這些字符進行URL編碼,URL編碼的方式是把須要編碼的字符轉化爲 %xx 的形式。
一般 URL 編碼是基於 UTF-8 的,函數說明也說起到給予UTF-8進行encode~
複製代碼
Ok,那就說,提取text的內容就好啦~那咱們先寫個請求吧
# -*- coding:utf-8 -*-
import requests
url = "https://m.weibo.cn/api/container/getIndex"
#請求的url
headers = {
"Host": "m.weibo.cn",
"Referer": "https://m.weibo.cn/u/1739928273",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36",
"Accept":'application/json, text/plain, */*',
"X-Requested-With":"XMLHttpRequest",
}
#請求頭
params = {
"type": "uid",
"value": "1739928273",
"containerid": "1076031739928273",
"page": "1"}
#請求攜帶的參數
res = requests.get(url,headers=headers,params=params).content
print(res)
複製代碼
執行後,獲得的結果是這樣的:
https://m.weibo.cn/api/container/getIndex?type=uid&value=1739928273&containerid=1076031739928273&page=1
複製代碼
接下來能夠幹嗎?就能夠寫正則來匹配啦,先找data,而後找cards,而後再獲取每一個cards下面的text;
若是真的如上面說的,立刻寫噼裏啪啦寫正則,就有點衝動了,看下返回結果的格式,感受是否是像json?
"ok":1,"data":{"cardlistInfo":{"containerid":"1076031739928273","v_p":
複製代碼
沒錯,這就是json,那咱們就能夠換一種方式處理~
res = requests.get(url,headers=headers,params=params)
cards = res.json().get("data").get("cards")
#獲取carads下的全部項
複製代碼
獲取的就是下面這個截圖的全部cards項:
那咱們看看cards裏面的內容,這是第一個:
嗯,有發現不一樣了嗎?對的,就是有多了個關注XXX的一項,可是這一項,可是這一項不是咱們要的,那怎麼搞?
逐個逐個分析,會發現,正常的數據都有這麼一項:
for card in cards:
if card.get("card_type") == 9:
text = card.get("mblog").get("text")
print(text)
複製代碼
輸出的結果以下:
回頭看了下,並非代碼的錯,並且由於發佈的內容有帶圖片或者表情~
這種狀況過濾掉就行了~只須要文字~
pattern = re.compile(r"(.*?)<span.*>(.*?)")
text = re.sub(pattern,"",text)
複製代碼
從上面能夠看到問題例子以下,那咱們只須要把裏面的內容都幹掉就行了~
啊啊啊啊啊啊啊啊啊
<span class = "url-icon"><img alt = [允悲] src = "https://user-gold-cdn.xitu.io/2018/6/29/1644b1bf47628785?w=32&h=32&f=png&s=2591" style = "width:1em; height:1em;"/></span>
複製代碼
結果以下:
這裏有個不解之謎,就是會看到,會有換行,緣由是這樣的:
以前在介紹urllib的時候說起有,urllib有一個quote的方法,函數說明說起到給予UTF-8進行encode;
import urllib
kw = urllib.request.quote("很緊張啊啊啊啊↵<s")
print(kw)
複製代碼
輸出的內容長這樣的:
%E5%BE%88%E7%B4%A7%E5%BC%A0%E5%95%8A%E5%95%8A%E5%95%8A%E5%95%8A%E2%86%B5%3Cs
複製代碼
那咱們把中文都去掉,只留↵看看?
%E2%86%B5
複製代碼
獲得的結果就是這樣的,OK,那假如咱們把上面這串結果匹配成空格,是否是就能解決問題?
但實際嘗試了下,是不行的,那咱們就把數據打出來:
啊啊啊啊啊啊啊啊啊
<s
複製代碼
最後會發現%0A纔是那個回車符
%8A%0A%3Cspan
複製代碼
去掉以後,會發現字符的確不見了,並且的的確不會換行了,問題解決;
kw = urllib.request.quote(text)
old_kw = re.sub("%0A","",kw)
new_kw = urllib.request.unquote(old_kw)
複製代碼
回到正題,按照上面的代碼爬下來的東西,好像沒啥問題,但認真一看,咦~
這裏誰說老師下垂了?
這裏,很明顯是以前的正則有問題,那咱們從新折騰下正則,此處過程就不說了,很痛苦。。最後改爲這樣:
pattern = re.compile(r"<.*?>")
複製代碼
意思就是把<>符號內的內容都去掉,得出的結果:
//@李太白的表哥:老師…你好像下垂了……
查看圖片
複製代碼
這裏能夠看到,查看圖片也是多餘的,那咱們也去掉,包括有一些是轉發微博的,也都幹掉吧,就成這樣了~
pattern = re.compile(r"<.*?>|轉發微博|查看圖片")
複製代碼
執行下,結果是這樣了,看上去很好:
//@李太白的表哥:老師…你好像下垂了……
複製代碼
ok,這個是一個頁面的內容抓取,總體代碼以下:
# -*- coding:utf-8 -*-
import requests
import re
import urllib
url = "https://m.weibo.cn/api/container/getIndex"
#請求的url
headers = {
"Host": "m.weibo.cn",
"Referer": "https://m.weibo.cn/u/1739928273",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36",
"Accept":'application/json, text/plain, */*',
"X-Requested-With":"XMLHttpRequest",
}
#請求頭
params = {
"type": "uid",
"value": "1739928273",
"containerid": "1076031739928273",
"page": "1"}
#請求攜帶的參數
res = requests.get(url,headers=headers,params=params)
cards = res.json().get("data").get("cards")
#獲取carads下的全部項
for card in cards:
if card.get("card_type") == 9:
text = card.get("mblog").get("text")
# kw = urllib.request.quote(text)
# old_kw = re.sub("%0A","",kw)
# new_kw = urllib.request.unquote(old_kw)
# %0A 這串數字對應的就是這個回車字符
pattern = re.compile(r"<.*?>|轉發微博|查看圖片")
#這裏就是把<>符號內的都匹配出來
text = re.sub(pattern,"",text)
print(text)
複製代碼
既然一頁搞定了,那咱們要爬多頁,怎麼破?這個很簡單啦,直接改page參數就好了
另外還遇到一個問題:
數據這多了,還發現這種東西~固然,也是正則兼容下就好了~
結果上面的處理,縫縫補補,最終代碼以下:
# -*- coding:utf-8 -*-
import requests
import re
import urllib
import codecs
url = "https://m.weibo.cn/api/container/getIndex"
#請求的url
headers = {
"Host": "m.weibo.cn",
"Referer": "https://m.weibo.cn/u/1761379670",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.87 Safari/537.36",
}
#請求頭
params = {
"type": "uid",
"value": "{uid}",
"containerid": "{containerid}",
"page":"{page}"}
#請求攜帶的參數
def get_Data(uid="3303658163", containerid="1005053303658163"):
total = 3000 #打算爬取的頁數,好比100頁
content = [] #存放獲取到的微博正文內容
page =1 #頁碼,從第一頁開始算
last_length = 0 #上一個的內容長度,用於對比上一次的整體內容長度跟此次是否一致,若是一致,則認爲沒有新數據,中止腳本處理
for i in range(total):
params["page"] = str(page)
params['uid'] = uid
params['containerid'] = str(containerid)
res = requests.get(url, headers=headers, params=params)
print(res.json().get("data"))
cards = res.json().get("data").get("cards")
# 獲取carads下的全部項
for card in cards:
if card.get("card_type") == 9:
text = card.get("mblog").get("text")
kw = urllib.request.quote(text)
old_kw = re.sub("%0A","",kw)
new_text = urllib.request.unquote(old_kw)
# %0A 這串數字對應的就是這個回車字符
pattern = re.compile(r"<.*?>|轉發微博|查看圖片|查看動圖|>")
#這裏就是把<>符號內的都匹配出來,正則規則
text = re.sub(pattern,"",new_text)
content.append(text)
page +=1
if (len(content) == last_length):
print("已經獲取不到更多內容,腳本暫停處理")
break
else:
last_length = len(content)
print("抓取第{page}頁,目前總共抓取了 {count} 條微博".format(page=page, count=len(content)))
with codecs.open('jb.txt', 'w', encoding='utf-8') as f:
f.write("\n".join(content))
if __name__ == '__main__':
get_Data("1761379670", "1005051761379670")
複製代碼
功能介紹的話,一路看下來就很明朗了,一句話就是,解析json而已;
可能有同窗問,上面的代碼如何使用?直接copy出來執行便可,若是想爬某人的信息,好比吉澤明步:
https://m.weibo.cn/u/2360092592?uid=2360092592&luicode=10000011&lfid=100103
type%3D1%26q%3D%E5%90%89%E6%B3%BD%E6%98%8E%E6%AD%A5
複製代碼
打開她的手機版微博主頁
最後的輸出結果以下:
該腳本可能依賴於網頁結果,一旦網頁結構發生變化,該腳本即不適用,請了解~
嘗試過20個左右的用戶,都可數據,如遇到問題,請留言告知,謝謝~
本文感謝三三同窗的極力支持,不然如研究PC版,估計就涼了~
本文主要解析怎麼爬取手機版的微博內容,主要原理是解析json,遇到有趣的問題有2個,第一是正則,想獲取什麼,把不須要的處理掉就行了,否則什麼都()去作,太麻煩了~第二,微博的換行符,一開始還想着\n匹配處理,結果發現不行,後來換個角度,弄成編碼的格式就發現問題了;
好了,本文到此,謝謝你們~