Python 爬蟲如何機器登錄新浪微博並抓取內容?

剛開始接觸爬蟲,不是很懂。嘗試照著網上的大神們給的資料一點點弄,但最後還是出現了寫問題。
我主要參照
模擬登錄新浪微博(Python)
python模擬新浪微博登陸功能(新浪微博爬蟲)_python_腳本之家,
成功從 prelogin.php 中獲得了那幾個參數,並加密得到su和sp放入post_data,最後顯示成功登陸(並返回retcode=0),接下來的步驟就不是很理解了。
我直接使用(url=http://weibo.com/u/2200453635,post_data,headers)來讀取html代碼,結果得到的還是和瀏覽器里看到的不一樣,有做過類似程序的大嬸給講解講解么?

req = urllib2.Request(
url = url, # url = "http://login.sina.com.cn/sso/login.php?client=ssologin.js(v1.4.15)" (怎麼找的?)
data = postdata, # servertime, nonce, rsakv, pubkey, su, sp
headers = headers # user_agent
)
result = urllib2.urlopen(req)
text = result.read() # 這讀出來的是什麼?
p = re.compile("location.replace("(.*?)")")
try:
login_url = p.search(text).group(1)
#print login_url
urllib2.urlopen(login_url)
print "登錄成功!"
except:
print "Login error!"
主要是這段代碼沒看懂。


前段時間在研究sina和twitter的數據,很久之前寫得一個模擬登陸的腳本沒用了,於是朋友給我發了一份有用的模擬登陸腳本,親測有效。

我改造了一下做的爬取微博評論的腳本效果如下:

下面是代碼,結合以下代碼理解一下,希望對你有用。

# -*- coding: utf-8 -*-
import requests
import base64
import re
import urllib
import urllib.parse
import rsa
import json
import binascii
from bs4 import BeautifulSoup

class Userlogin:
def userlogin(self,username,password,pagecount):
session = requests.Session()
url_prelogin = "http://login.sina.com.cn/sso/prelogin.php?entry=weibocallback=sinaSSOController.preloginCallBacksu=rsakt=modclient=ssologin.js(v1.4.5)_=1364875106625"
url_login = "http://login.sina.com.cn/sso/login.php?client=ssologin.js(v1.4.5)"

#get servertime,nonce, pubkey,rsakv
resp = session.get(url_prelogin)
json_data = re.findall(r"(?&<=().*(?=))", resp.text)[0] data = json.loads(json_data) servertime = data["servertime"] nonce = data["nonce"] pubkey = data["pubkey"] rsakv = data["rsakv"] # calculate su print(urllib.parse.quote(username)) su = base64.b64encode(username.encode(encoding="utf-8")) #calculate sp rsaPublickey= int(pubkey,16) key = rsa.PublicKey(rsaPublickey,65537) message = str(servertime) +" " + str(nonce) + " " + str(password) sp = binascii.b2a_hex(rsa.encrypt(message.encode(encoding="utf-8"),key)) postdata = { "entry": "weibo", "gateway": "1", "from": "", "savestate": "7", "userticket": "1", "ssosimplelogin": "1", "vsnf": "1", "vsnval": "", "su": su, "service": "miniblog", "servertime": servertime, "nonce": nonce, "pwencode": "rsa2", "sp": sp, "encoding": "UTF-8", "url": "http://weibo.com/ajaxlogin.php?framelogin=1callback=parent.sinaSSOController.feedBackUrlCallBack", "returntype": "META", "rsakv" : rsakv, } resp = session.post(url_login,data=postdata) # print resp.headers print(resp.content) login_url = re.findall(r"http://weibo.*retcode=0",resp.text) # print(login_url) respo = session.get(login_url[0]) uid = re.findall(""uniqueid":"(d+)",",respo.text)[0] url = "http://weibo.com/u/"+uid respo = session.get(url)


教你一個爬蟲小技巧:所有社交網站爬蟲,優先選擇爬移動版,比如:http://m.weibo.com


啊喂,你們不要只收藏不點贊啊 = =
稍微更新一下,多說兩句。
雖然爬取移動端比較簡單,但是爬一點難的東西對身體好對吧。
總結一下這個模擬登陸涉及的東西:
1.用戶名經過base64加密。
2.輸入用戶名後會進行預登陸操作。
3.密碼明文與一些其它的字元串參數拼接後,使用RSA加密,再提交給伺服器,其中RSA公鑰和各種參數都可以從預登陸操作返回的結果中找到。
4.會出現兩個跳轉。

所以思路如下:
1.用base64加密用戶名之後仿造一個預登陸,用正則匹配得到各項參數。
2.用上一步里得到的參數,拼接密碼明文,再用RSA加密得到密文,並構造POST的form data。
3.使用構造好的form data仿造登錄請求
4.用正則匹配獲得跳轉的目標鏈接。
5.為了保持登陸,用cookiejar一類的工具綁定一個cookie就行了。

======以下原答案=======
剛寫完這個爬蟲。。
新浪這東西做的煞是噁心。
代碼和分析過程寫在我blog里了。
http://shrik3.com/2016/03/25/sina-login/

測試可以用。
有理解不對的地方歡迎聚聚們指正
。。
你說的最後那段代碼,是從重定向頁面中獲取新的url然後繼續登陸,然而少了一步喔。


你問,為什麼瀏覽器中看到的跟程序里獲取的html不一樣。我推斷你對網頁從一個文本文件到你所看到得樣子這期間經歷了什麼不甚了解。瀏覽器里所看到的跟你用程序抓取的看到不一樣是因為網頁文本中的javascript代碼會被瀏覽器解析執行。而javascript會修改頁面dom結構。但是python中網頁文本中的javascript不會被解析執行。建議了解一下瀏覽器解析網頁過程。
工欲善其事,必先利其器。推薦你看一下這個項目 binux/pyspider · GitHub 。另外開闊思路的項目 ariya/phantomjs · GitHub 、 n1k0/casperjs · GitHub 。
最後經驗,抓取網頁的話 wap站 &> m站 &> pc站 。微博wap站無js,表單結構簡單清晰。適合初學拿來學習抓取。做微博爬蟲,微博機器人沒事千萬別在微博上關注微博反垃圾團隊的工程師,因為他們很可能互粉你,別問我為什麼知道滴。


GitHub - xchaoinfo/fuck-login: 模擬登錄一些知名的網站,為了方便爬取需要登錄的網站
一個模擬登陸的小項目,已經解決了,新浪微博,百度,知乎,京東,微信網頁版等一些網站的模擬登錄。
歡迎來 fork and pull request

項目中提供了 http://weibo.com 和 http://m.weibo.cn 登錄方式

另外提供一種解析 http://weibo.com 網頁的方式

html = requests.get(url, headers=headers)
content = html.text
pa = r"STK.pageletM.view(({"pid":"pl_user_feedList".*}))&"
res = re.findall(pa, content)
print(len(res))
js = json.loads(res[0])
html = js["html"]
soup = BeautifulSoup(html, "lxml")

微信公眾號 xchaoinfo 歡迎關注


難點在於模擬登陸,登陸後不管直接抓網頁還是調用API都好辦,前者抓包仔細檢查返回內容,後者抽時間閱讀API,不過API有限制調用次數。
以前在研究的時候,找到一個不需要驗證碼的入口:新浪通行證登錄
登陸代碼見我博文中的第一種方法:Python 模擬登錄新浪微博的兩種方法


之前寫過一個調用新浪微博api的教程,其中就有如何用python登錄新浪然後獲得調用api時所需要的code,把這一段貼到這裡來:

想要自動獲得code值就是要解決如何獲得授權界面之後的登錄問題,這個問題也困擾了我很久
起初我是手動登錄第一次,然後直接用chrome查看發送的請求,將其中的cookies複製下來,每次直接發送get請求獲得回調網頁獲得code值,如下:

get_code_url=requests.get(url,cookies=cook).url
code=get_code_url.url[47:]

這方法老實說十分方便,不用分析太多新浪登錄的方法,但當我調用api次數受限制之後,這個方法又不管用了
當一個應用的調用api受限之後我們可以創建多個新浪帳號多個應用,獲得多個App key和App Secret來反覆調用,這樣就一定要解決如何自動登錄新浪獲取code的問題
首先我們要分析新浪微博的登錄過程,我用chrome、edge、ie還是fiddler4都不能完全抓取完整登錄過程,最後試了firefox才成功抓去了整個登錄的過程

雖然只輸入了一次帳號密碼但是發送了兩次post請求

我們逐條請求來分析一下:
base64加密過後的用戶名,後面會講如何實現,我隨便改的,大家知道意思就好)
請求成功之後伺服器會給我們返回一段信息,其中有我們在後面會用到的參數

sinaSSOController.preloginCallBack({"retcode":0,"servertime":1450667800,"pcid":"gz-fee1d39aaf203ccc63dc783a13ccce11413a","nonce":"1HRSQP","pubkey":"EB2A38568661887FA180BDDB5CABD5F21C7BFD59C090CB2D245A87AC253062882729293E5506350508E7F9AA3BB77F4333231490F915F6D63C55FE2F08A49B353F444AD3993CACC02DB784ABBB8E42A9B1BBFFFB38BE18D78E87A0E41B9B8F73A928EE0CCEE1F6739884B9777E4FE9E88A1BBE495927AC4A799B3181D6442443","rsakv":"1330428213","is_openlock":0,"showpin":0,"exectime":18})
其中servertime、nonce、pubket和rsakv這幾個值是我們後面需要的,我們需要將其解析出來:

get_arg=requests.get(get_arg_url)
get_arg_content=get_arg.content
get_arg_content_split=get_arg_content.split(",")
servertime=get_arg_content_split[1].split(":")[1]
nonce=get_arg_content_split[3].split(":")[1][1:-1]
pubkey=get_arg_content_split[4].split(":")[1][1:-1]
rsakv=get_arg_content_split[5].split(":")[1][1:-1]

接著我們來看第二條post請求
第二條請求向新浪通行證發送一個表單

其中servertime、nonce、pubket和rsakv便是我們在上一個get請求中得到的,su就是加密過後的帳號,sp就是加密過後的密碼
su的加密方式是base64,先安裝一個base64的庫,然後調用如下函數:

su=base64.encodestring(username)[:-1]

密碼的加密方式要稍微複雜一點,還要用到servertime、nonce、pubket和rsakv:

rsaPublickey = int(pubkey, 16)
key = rsa.PublicKey(rsaPublickey, 65537) #創建公鑰
message = str(servertime) + " " + str(nonce) + "
" + str(password)
sp = rsa.encrypt(message, key) #加密
sp = binascii.b2a_hex(sp) #將加密信息轉換為16進位。

密碼的加密需要用到binascii庫和rsa庫
發送完這個請求之後伺服器會返回一個JSON數據,其中有一個ticket是我們待會兒要用到的

請求並獲得ticket代碼如下:

postPara = {
"entry": "openapi",
"gateway": "1",
"from":"",
"savestate": "0",
"userticket": "1",
"pagerefer":"",
"ct": "1800",
"s":"1",
"vsnf": "1",
"vsnval": "",
"door":"",
"appkey":"52laFx",
"su": su,
"service": "miniblog",
"servertime": servertime,
"nonce": nonce,
"pwencode": "rsa2",
"rsakv" : rsakv,
"sp": sp,
"sr":"1920*1080",
"encoding": "UTF-8",
"cdult":"2",
"domain":"weibo.com",
"prelt":"2140",
"returntype": "TEXT",
}
get_ticket_url="https://login.sina.com.cn/sso/login.php?client=ssologin.js(v1.4.15)_=1450667802929"
req=requests.post(get_ticket_url,postPara)
print req.content
ticket=req.content.split(",")[1].split(":")[1][1:-1]

然後是第三條請求
第三條請求仍然是post請求,向第三方授權錯誤發的請求,這一個表單的內容就是直接在html代碼中給出了

其中client_id是我們的APP_KEY;redirect_url是我們的回調頁面,就是我們一開始建立應用時設置的;regCallback具體我不知道是哪來的,但是其中有兩個變數,一個是APP_KEY,一個就是我們設置的回調頁面;其它的表單內容都是固定的。請求代碼如下:

fields={
"action": "login",
"display": "default",
"withOfficalFlag": "0",
"quick_auth": "null",
"withOfficalAccount": "",
"scope": "",
"ticket": ticket,
"isLoginSina": "",
"response_type": "code",
"regCallback": "https://api.weibo.com/2/oauth2/authorize?client_id="+APP_KEY+"response_type=codedisplay=defaultredirect_uri="+CALLBACK_URL+"from=with_cookie=",
"redirect_uri":CALLBACK_URL,
"client_id":APP_KEY,
"appkey62": "52laFx",
"state": "",
"verifyToken": "null",
"from": "",
"switchLogin":"0",
"userId":"",
"passwd":""
}
headers = {
"User-agent": "Mozilla/5.0 (Windows NT 10.0; WOW64; rv:43.0) Gecko/20100101 Firefox/43.0",
"Referer": url,
"Content-Type": "application/x-www-form-urlencoded"}
post_url="https://api.weibo.com/oauth2/authorize"
get_code_url=requests.post(post_url,data=fields,headers=headers)

最後在從響應成功的get_code_url將code值分析出來即可

code=get_code_url.url[47:]

這樣我們就成功自動的獲取了code值

原文地址:python模擬登錄新浪微博自動獲得調用新浪api所需的code


我在github上放過兩個爬蟲,可供參考。
GitHub - wu-yuanyi/crawler: There are some crawlers that I writed.

都是自己用python3寫的,用到一下的庫:

urllib.request,urllib.parse,re,urllib.error,socket

  1. researchgate.py是幫某個華師大情報學碩士寫的畢設程序。在researchgate按關鍵詞搜索論文,然後爬取題目,作者。https,需要登錄,網站會反爬蟲(頻率高了會封號)
  2. uniprot.py是幫人類研究所的一個同學,爬取蛋白質信息寫的爬蟲。
  3. baidu.py是我自己還寫過爬百度APP市場的爬蟲。涉及到我的論文中的一小部分,還沒放上去。不過中間一點經驗還可以說下:

urllib.request.urlopen(request,timeout=300)

記得設置timeout,之後的read()才不會卡主
需要的Exception有:

socket.timeout,urllib.error.HTTPError,IncompleteRead

因為我遇到過 gateerror,404。
---------------吐槽的分割線----------------------
吐槽百度:

  1. 推薦榜單上的一些app,居然下載鏈接還是空的,比如果殼網果殼網_生活實用類果殼網軟體下載
  2. 推薦榜單上的一些app,換了個名字,裡面都是一毛一樣的。

吐槽GFW:
我是多麼想分析google app store的啊。ARM的emulator已經夠慢了,還是不要找罪受了。。。


代碼地址:GitHub - GannicusLiu/Crawler

# 新浪微博模擬登錄

### 登錄地址
http://weibo.com/login.php
把該頁面的cookie取下來,後面登錄發請求的時候需要用到

### 獲取前置登錄所需參數
#### 請求地址
http://login.sina.com.cn/sso/prelogin.php?entry=weibocallback=sinaSSOController.preloginCallBacksu=rsakt=modclient=ssologin.js(v1.4.18)_=1463016085877
#### 返回結果
sinaSSOController.preloginCallBack({"retcode":0,"servertime":1463016089,"pcid":"gz-12a8a1ae997f9fafb79edd1445fae679f4a1","nonce":"JHVO2Z","pubkey":"EB2A38568661887FA180BDDB5CABD5F21C7BFD59C090CB2D245A87AC253062882729293E5506350508E7F9AA3BB77F4333231490F915F6D63C55FE2F08A49B353F444AD3993CACC02DB784ABBB8E42A9B1BBFFFB38BE18D78E87A0E41B9B8F73A928EE0CCEE1F6739884B9777E4FE9E88A1BBE495927AC4A799B3181D6442443","rsakv":"1330428213","uid":"1893131633","exectime":174})

#### 匹配參數
用正則表達式獲取json包解析出servertime、pcid、nonce、pubkey、rsakv
- servertime 伺服器時間
- pcid 下載登錄驗證碼時會用到
- nonce 隨機串 RSA加密密碼時會用到
- pubkey RSA加密的公鑰
- rsakv 登錄參數

### 分析登錄參數組裝
http://login.sina.com.cn/js/sso/ssologin.js
#### 微博用戶名(su)加密規則
見http://login.sina.com.cn/js/sso/ssologin.js 312行
sinaSSOEncoder.base64.encode(urlencode(username));
#### 微博用戶密碼(sp)加密規則
見http://login.sina.com.cn/js/sso/ssologin.js 902行
if ((me.loginType rsa) me.servertime sinaSSOEncoder sinaSSOEncoder.RSAKey) {
request.servertime = me.servertime;
request.nonce = me.nonce;
request.pwencode = "rsa2";
request.rsakv = me.rsakv;
var RSAKey = new sinaSSOEncoder.RSAKey();
RSAKey.setPublic(me.rsaPubkey, "10001");
password = RSAKey.encrypt([me.servertime, me.nonce].join(" ") + "
" + password)
}

### 驗證碼地址
http://login.sina.com.cn/cgi/pin.php?r=14749233s=0p=hk-4a80803307d47c997fa630d4109531dafc8e
根據前置登錄獲取到的參數showpin
當showpin為1時需要驗證碼,當為0時不需要驗證碼
需要驗證碼時,把驗證碼圖保存下來,手工輸入或者自動識別

### 登錄
#### 請求地址
http://login.sina.com.cn/sso/login.php?client=ssologin.js(v1.4.18)
#### 請求參數
entry=weibo
gateway=1
from=
savestate=0
useticket=1
pagerefer=
vsnf=1
su=編碼過後的微博用戶名
service=miniblog
servertime=前置登錄參數
nonce=前置登錄參數
pwencode=rsa2
rsakv=前置登錄參數
sp=機密後的密碼
sr=1366*768
encoding=UTF-8
prelt=1279
url=http%3A%2F%2Fweibo.com%2Fajaxlogin.php%3Fframelogin%3D1%26callback%3Dparent.sinaSSOController.feedBackUrlCallBack
returntype=META
door=驗證碼 需要驗證碼的時候才傳遞該參數

#### 返回結果
`location.replace("http://passport.weibo.com/wbsso/login?url=http%3A%2F%2Fweibo.com%2Fajaxlogin.php%3Fframelogin%3D1%26callback%3Dparent.sinaSSOController.feedBackUrlCallBack%26sudaref%3Dweibo.comticket=ST-MTg5MzEzMTYzMw==-1464838377-gz-E4356F083C2998D105269B1FA6BE6F5Aretcode=0");});}`
把location.replace中的url匹配出來

### 請求passport
#### 請求url
登錄返回的結果中匹配出來的url
#### 返回結果
該請求返回的header中有個302跳轉
Location: http://weibo.com/ajaxlogin.php?framelogin=1callback=parent.sinaSSOController.feedBackUrlCallBacksudaref=weibo.com

### 302跳轉
#### 返回內容
如果返回如下內容,表示登錄成功了 uniqueid是我在新浪微博的全局唯一ID,我這裡隱去了
&&&

爬蟲就是這麼簡單。這麼easy。有了python,再也不用擔心指針越界內存回收了。哈哈哈。


單從學習的角度來講,無論是微博模擬登陸還是抓取並且解析微博數據,難度都比一般的爬蟲難度要高很多。模擬登陸的難度題主已經領略到了,如果你在成功登錄後,抓取了微博,去解析返回的數據,就會遇到很多問題。最為明顯的問題就是你在瀏覽器中看到的數據,拿到網頁源碼上去搜,卻搜不出來,因為它的真實數據都通過

FM.view((.*))

這個正則表達式包裹起來了。

模擬登陸和這個應該可以難住一部分同學了。更為複雜的其實是如何把數據拿的比較全面,舉個例子,微博的用戶包括了很多類別,比如domain為100505的普通用戶,domain為100305的作家,domain為100206的企業號,我看了很多爬蟲都粗糙的將其處理為100505,又舉個例子,比如微博評論查看更多的時候,有時候是通過下拉來獲取更多的評論數據,有時候是點擊通過『查看更多』來獲取更多評論,這個也需要很細緻的研究才能把數據獲取完整。和它之類的還有用戶主頁所有微博的抓取等,都會有一些坑,需要做大量的測試。當然,我說的這些都是PC端的東西,移動端的登錄和解析難度要小很多,當然,它的壞處也是比較明顯的,就是信息不全。

所以,下面是重點:我開源了一個分散式的微博爬蟲,目前有少量幾個用戶,並且反饋良好。無論你是學習爬蟲的,還是需要微博數據的,我覺得它都能幫到你。項目並沒有使用scrapy-redis,而是使用celery作為任務調度。而且我看了網上分享的幾乎所有分散式爬蟲都沒使用過celery!因為它們的爬蟲任務可能比較簡單,該項目的爬蟲任務比較複雜,幾乎涵蓋了你能想到的所有的和微博相關的數據的抓取,所以從任務優先順序和耗時性的角度出發,任務路由幾乎是必須的。這也是我選擇celery做為分散式任務調度的一個很重要的因素。


下面是項目地址:ResolveWang/WeiboSpider


歡迎大佬拍磚,小白詢問一些關於項目的問題


這個好像是初學爬蟲必修課。。。爬微博,微博好可憐。以下是乾貨:
1、微博可以直接爬移動版: http://weibo.cn;
2、關於pc版的模擬登錄分析,可以參考我之前的文章,應該是幫助了不少人,最近還有人微博私信我的,地址:python 新浪微博模擬登陸 密碼加密分析_The_Third_Wave_新浪博客;
3、關於使用微博api,昨天接到升級通知,好像限制ip使用應用了,不知道還可以用否,但是當時的筆記,還是很有用的,同樣,最近還能收到關於微博api使用的諮詢私信,地址如下:
Python:新浪微博API的使用及安全的模擬登陸自動獲取code值,微博API怎麼爬取其他未授權用戶的微博/怎麼爬取指定用戶發布的微博。


用了 selenium 這個庫,selenium 的安裝可以參考selenium的安裝與使用, 然後很輕鬆的就登錄上了新浪微博,如果你想全部後台操作再結合 PhantomJS,具體代碼如下:

1 #! env/bin/python3
2 # -*- encoding:utf-8 -*-
3
4 from selenium import webdriver
5 from selenium.webdriver.common.keys import Keys
6
7 url = "http://www.weibo.com/login.php"
8 driver = webdriver.Firefox()
9 driver.get(url)
10 username = driver.find_element_by_name("username")
11 username.clear()
12 username.send_keys("賬號")
13 password = driver.find_element_by_name("password")
14 password.clear()
15 password.send_keys("密碼")
16 driver.find_element_by_xpath("//*[@id="pl_login_form"]/div/div[3]/div[6]/a") .click()


爬取移動版的微博網頁更有效


url = url, # url = "...." (怎麼找的?)

人工找的, 在你爬一個網頁之前要進行踩點, 既然要模擬登錄, 當然要人工找到登錄的頁面, 在請求中填入預先準備好的表單信息及http頭並通過urllib提交表單(data=postdata, headers = headers這兩句)

text = result.read() # 這讀出來的是什麼?

讀的是頁面源代碼, 但這個頁面源代碼跟我們瀏覽器看到的頁面並不完全一致, 這是經過js處理的, 你截圖裡看到div里沒有內容, 排除認證失敗或者操作錯誤的原因則說明這個div的內容是經過js處理輸出的. 這對爬蟲來說不是個好消息, 因為它意味著我們的爬蟲要對js進行處理, 我所知道的方法是用一些可以模擬瀏覽器行為的python庫,如selenium、webdriver.
可以參考下這個問題:Python 爬蟲如何獲取 JS 生成的 URL 和網頁內容? - JavaScript
不過我認為這種方法多少有點費勁了, 可以爬取這個頁面的移動版來達到更好的效果.

寫爬蟲的時候還早用瀏覽器的查看源代碼功能吧, 這才是爬蟲看到的真實頁面.

如果是要實現模擬登錄的話, 推薦用截包工具Fiddler free web debugging proxy, 這個工具無論是用來前端調試還是截包分析都是個神器.
比如說, 在Fiddler的攔截下, 你可以試著把瀏覽器在該網站下的cookie和session清掉, 然後刷新一下. 觀察有無cookie兩個請求返回頁面的差距, 再用Fiddler手工填寫表單內容試一下登錄, 接著只要用python的http庫模擬發出一個一樣的登錄請求, 並把cookie保存下來就可以了.不知道說的是否清楚, 如果無法理解的話我再補充回答吧.


可以用微博的API做,
帳號+密碼獲取taken,
然後調用API獲取微博就可以了。
微博有Python API介面的。


可以使用selenium包模擬瀏覽器訪問。通過定位頁面元素,可以找到登陸按鈕和輸入框,輸入登錄信息後登陸。

然後可以另瀏覽器將頁面拽到最下方,因為往下拽的時候下面的微博才會顯示出來(pc網頁版),再繼續往下拽才會出現下一頁按鈕。這時可以爬到該頁面上所有的微博內容,然後模擬點擊下一頁,對下一頁做同樣的事情就好啦~

總之用selenium可以隨意定位頁面元素,可以完全模擬人瀏覽頁面的方式,缺點就是速度比較慢,需要有瀏覽器。


ref:自己的代碼
https://github.com/dorophy1995/fetchweibo#enjoy-it


以前用過python寫過一些簡單的爬蟲,最近使用phantomjs嘗試寫了一個登錄新浪PC站點並獲取頁面內容的爬蟲(驗證碼需自己輸入),給大家一個參考:https://github.com/zhangw/phantomjs_search_weibo。
1.客戶端登錄驗證部分,我直接將新浪的js納為己用,(做了一些很簡單的修改)
2.驗證碼圖片獲取之後,需用戶自己輸入
3.頁面內容的獲取嘛,使用jquery或者原生DOM的API,或者你直接使用新浪實現的對象選擇器(我用了一下)。
4.調試登錄驗證時,兩大利器,chrome瀏覽器查看方法調用堆棧,利於迅速理解新浪的js代碼層次結構(firefox/safari我用的不多,但應該都一樣用),網路請求分析,我在mac上用的是charles(不過應該是fiddler更好用)


其實很簡單,模擬提交一些數據,你先用抓包工具把正常登陸時發送的欄位都記錄下來,然後一個個模擬,建議不要直接模擬登錄pc版的先試試wap版的


#coding:utf-8
from __future__ import (
print_function,
unicode_literals)
import requests
import re
import json
import base64
import time
import math
import random
from PIL import Image
try:
from urllib.parse import quote_plus
except:
from urllib import quote_plus

"""
1.用base64加密用戶名之後仿造一個預登陸,用正則匹配得到各項參數
2.用上一步里得到的參數,拼接密碼明文,再用RSA加密得到密文,並構造POST的form data。
3.使用構造好的form data仿造登錄請求
4.用正則匹配獲得跳轉的目標鏈接。
5.為了保持登陸,使用session保存cookie。
"""

#構造 Request 的headers部分
agent = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36 QIHU 360EE"

headers = {
"Host": "passport.weibo.cn",
"Connection": "keep-alive",
"Upgrade-Insecure-Requests": "1",
"User-Agent": agent
}

"""
會話對象requests.Session能夠跨請求地保持某些參數,
比如cookies,即在同一個Session實例發出的所有請求都保持同一個cookies,
而requests模塊每次會自動處理cookies,這樣就很方便地處理登錄時的cookies問題。
"""

session = requests.session()

#訪問登陸頁面
index_url="https://passport.weibo.cn/signin/login"
#獲得
session.get(index_url,headers=headers)

def get_su(username):
"""
對用戶名進行base64編碼,返回編碼後的usernamebase64字元串
:param username:
:return:username_base64
"""
username_url=quote_plus(username)
username_base64 = base64.b64encode(username_url.encode("utf-8"))
return username_base64.decode("utf-8")

def login_pre(username):
"""
預登陸
:param username:
:return:
"""
params = {
"checkpin": "1",
"entry": "mweibo",
"su": get_su(username),
"callback": "jsonpcallback" + str(int(time.time() * 1000) + math.floor(random.random() * 100000))
}
pre_url= "https://login.sina.com.cn/sso/prelogin.php"
headers["Host"] = "login.sina.com.cn"
headers["Referer"] = index_url
pre = session.get(pre_url, params=params, headers=headers)
#print(pre.text)
#res = re.findall(r"((.*?))",pre.text)

if pre.text == "" :
print("預登陸失敗")
else:
js = pre.json()
#js = json.loads(js)
if js["showpin"] == 1:
headers["Host"] = "passport.weibo.cn"
capt = session.get("https://passport.weibo.cn/captcha/image", headers=headers)
capt_json = capt.json()
capt_base64 = capt_json["data"]["image"].split("base64,")[1]
with open("capt.jpg", "wb") as f:
f.write(base64.b64decode(capt_base64))
f.close()
im = Image.open("capt.jpg")
im.show()
im.close()
cha_code = input("請輸入驗證碼
&>")
return cha_code, capt_json["data"]["pcid"]
else:
return ""

def login (username, password, pincode):
postdata = {
"username" : username,
"password" : password,
"savestate" : "1",
"ec" : "0",
"pagerefer" : "",
"entry" : "mweibo",
"wentry" : "",
"loginfrom" :"",
"client_id" : "",
"code" : "",
"qq" : "",
"mainpageflag" :"1",
"hff" :""
}
if pincode == "":
pass
else:
postdata["pincode"] = pincode[0]

postdata["pcid"] = pincode[1]
headers["Host"] = "passport.weibo.cn"
headers["Reference"] = index_url
headers["Origin"] = "https://passport.weibo.cn"
headers["Content-Type"] = "application/x-www-form-urlencoded"
post_url = "https://passport.weibo.cn/sso/login"
login = session.post(post_url, data=postdata, headers=headers)
# print(login.cookies)
# print(login.status_code)
js = login.json()
# print(js)
uid = js["data"]["uid"]
crossdomain = js["data"]["crossdomainlist"]
cn = "https:" + crossdomain["sina.com.cn"]
# 下面兩個對應不同的登錄 weibo.com 還是 m.weibo.cn
# 一定要注意更改 Host
# mcn = "https:" + crossdomain["weibo.cn"]
# com = "https:" + crossdomain["weibo.com"]
headers["Host"] = "login.sina.com.cn"
session.get(cn, headers=headers)
headers["Host"] = "weibo.cn"
ht = session.get("http://weibo.cn/%s/info" % uid, headers=headers)
# print(ht.url)
# print(session.cookies)
pa = r"&(.*?)&"
res = re.findall(pa, ht.text)
print("模擬登錄%s" % res[0][0:-3])
home=session.get("https://m.weibo.cn/",headers=headers)
print(home.text)
# print(cn, com, mcn)

if __name__ == "__main__":
username = "你的賬號"
password = "你的密碼"
pincode = login_pre(username)
login(username, password, pincode)


推薦閱讀:

請問爬蟲如何爬取動態頁面的內容?
如何爬網易雲音樂的評論數?
如何開發高級Python爬蟲?
python多線程爬蟲設計?
學習爬蟲應該從哪裡學起?

TAG:新浪微博 | Python | 爬蟲計算機網路 | Cookie |