Python爬蟲抓取微博評論

来源:https://www.cnblogs.com/yangmaosen/archive/2020/03/07/12439273.html
-Advertisement-
Play Games

第一步:引入庫 import time import base64 import rsa import binascii import requests import re from PIL import Image import random from urllib.parse import qu ...


第一步:引入庫

import time
import base64
import rsa
import binascii
import requests
import re
from PIL import Image
import random
from urllib.parse import quote_plus
import http.cookiejar as cookielib
import csv
import os

 

第二步:一些全局變數的設置

comment_path = 'comment'
agent = 'mozilla/5.0 (windowS NT 10.0; win64; x64) appLewEbkit/537.36 (KHTML, likE gecko) chrome/71.0.3578.98 safari/537.36'
headers = {'User-Agent': agent}

 

第三步:創立目錄作為存放數據的

if not os.path.exists(comment_path):
os.mkdir(comment_path)

 

第四步:登陸類的創立

class WeiboLogin(object):
"""
通過登錄 weibo.com 然後跳轉到 m.weibo.cn
"""

# 初始化數據
def __init__(self, user, password, cookie_path):
super(WeiboLogin, self).__init__()
self.user = user
self.password = password
self.session = requests.Session()
self.cookie_path = cookie_path
# LWPCookieJar是python中管理cookie的工具,可以將cookie保存到文件,或者在文件中讀取cookie數據到程式
self.session.cookies = cookielib.LWPCookieJar(filename=self.cookie_path)
self.index_url = "http://weibo.com/login.php"
self.session.get(self.index_url, headers=headers, timeout=2)
self.postdata = dict()

def get_su(self):
"""
對 email 地址和手機號碼 先 javascript 中 encodeURIComponent
對應 Python 3 中的是 urllib.parse.quote_plus
然後在 base64 加密後decode
"""
username_quote = quote_plus(self.user)
username_base64 = base64.b64encode(username_quote.encode("utf-8"))
return username_base64.decode("utf-8")

# 預登陸獲得 servertime, nonce, pubkey, rsakv
def get_server_data(self, su):
"""與原來的相比,微博的登錄從 v1.4.18 升級到了 v1.4.19
這裡使用了 URL 拼接的方式,也可以用 Params 參數傳遞的方式
"""
pre_url = "http://login.sina.com.cn/sso/prelogin.php?entry=weibo&callback=sinaSSOController.preloginCallBack&su="
pre_url = pre_url + su + "&rsakt=mod&checkpin=1&client=ssologin.js(v1.4.19)&_="
pre_url = pre_url + str(int(time.time() * 1000))
pre_data_res = self.session.get(pre_url, headers=headers)
# print("*"*50)
# print(pre_data_res.text)
# print("*" * 50)
sever_data = eval(pre_data_res.content.decode("utf-8").replace("sinaSSOController.preloginCallBack", ''))

return sever_data

def get_password(self, servertime, nonce, pubkey):
"""對密碼進行 RSA 的加密"""
rsaPublickey = int(pubkey, 16)
key = rsa.PublicKey(rsaPublickey, 65537) # 創建公鑰
message = str(servertime) + '\t' + str(nonce) + '\n' + str(self.password) # 拼接明文js加密文件中得到
message = message.encode("utf-8")
passwd = rsa.encrypt(message, key) # 加密
passwd = binascii.b2a_hex(passwd) # 將加密信息轉換為16進位。
return passwd

def get_cha(self, pcid):
"""獲取驗證碼,並且用PIL打開,
1. 如果本機安裝了圖片查看軟體,也可以用 os.subprocess 的打開驗證碼
2. 可以改寫此函數接入打碼平臺。
"""
cha_url = "https://login.sina.com.cn/cgi/pin.php?r="
cha_url = cha_url + str(int(random.random() * 100000000)) + "&s=0&p="
cha_url = cha_url + pcid
cha_page = self.session.get(cha_url, headers=headers)
with open("cha.jpg", 'wb') as f:
f.write(cha_page.content)
f.close()
try:
im = Image.open("cha.jpg")
im.show()
im.close()
except Exception as e:
print(u"請到當前目錄下,找到驗證碼後輸入")

def pre_login(self):
# su 是加密後的用戶名
su = self.get_su()
sever_data = self.get_server_data(su)
servertime = sever_data["servertime"]
nonce = sever_data['nonce']
rsakv = sever_data["rsakv"]
pubkey = sever_data["pubkey"]
showpin = sever_data["showpin"] # 這個參數的意義待探索
password_secret = self.get_password(servertime, nonce, pubkey)

self.postdata = {
'entry': 'weibo',
'gateway': '1',
'from': '',
'savestate': '7',
'useticket': '1',
'pagerefer': "https://passport.weibo.com",
'vsnf': '1',
'su': su,
'service': 'miniblog',
'servertime': servertime,
'nonce': nonce,
'pwencode': 'rsa2',
'rsakv': rsakv,
'sp': password_secret,
'sr': '1366*768',
'encoding': 'UTF-8',
'prelt': '115',
"cdult": "38",
'url': 'http://weibo.com/ajaxlogin.php?framelogin=1&callback=parent.sinaSSOController.feedBackUrlCallBack',
'returntype': 'TEXT' # 這裡是 TEXT 和 META 選擇,具體含義待探索
}
return sever_data

def login(self):
# 先不輸入驗證碼登錄測試
try:
sever_data = self.pre_login()
login_url = 'https://login.sina.com.cn/sso/login.php?client=ssologin.js(v1.4.19)&_'
login_url = login_url + str(time.time() * 1000)
login_page = self.session.post(login_url, data=self.postdata, headers=headers)
ticket_js = login_page.json()
ticket = ticket_js["ticket"]
except Exception as e:
sever_data = self.pre_login()
login_url = 'https://login.sina.com.cn/sso/login.php?client=ssologin.js(v1.4.19)&_'
login_url = login_url + str(time.time() * 1000)
pcid = sever_data["pcid"]
self.get_cha(pcid)
self.postdata['door'] = input(u"請輸入驗證碼")
login_page = self.session.post(login_url, data=self.postdata, headers=headers)
ticket_js = login_page.json()
ticket = ticket_js["ticket"]
# 以下內容是 處理登錄跳轉鏈接
save_pa = r'==-(\d+)-'
ssosavestate = int(re.findall(save_pa, ticket)[0]) + 3600 * 7
jump_ticket_params = {
"callback": "sinaSSOController.callbackLoginStatus",
"ticket": ticket,
"ssosavestate": str(ssosavestate),
"client": "ssologin.js(v1.4.19)",
"_": str(time.time() * 1000),
}
jump_url = "https://passport.weibo.com/wbsso/login"
jump_headers = {
"Host": "passport.weibo.com",
"Referer": "https://weibo.com/",
"User-Agent": headers["User-Agent"]
}
jump_login = self.session.get(jump_url, params=jump_ticket_params, headers=jump_headers)
uuid = jump_login.text

uuid_pa = r'"uniqueid":"(.*?)"'
uuid_res = re.findall(uuid_pa, uuid, re.S)[0]
web_weibo_url = "http://weibo.com/%s/profile?topnav=1&wvr=6&is_all=1" % uuid_res
weibo_page = self.session.get(web_weibo_url, headers=headers)

# print(weibo_page.content.decode("utf-8")

Mheaders = {
"Host": "login.sina.com.cn",
"User-Agent": agent
}

# m.weibo.cn 登錄的 url 拼接
_rand = str(time.time())
mParams = {
"url": "https://m.weibo.cn/",
"_rand": _rand,
"gateway": "1",
"service": "sinawap",
"entry": "sinawap",
"useticket": "1",
"returntype": "META",
"sudaref": "",
"_client_version": "0.6.26",
}
murl = "https://login.sina.com.cn/sso/login.php"
mhtml = self.session.get(murl, params=mParams, headers=Mheaders)
mhtml.encoding = mhtml.apparent_encoding
mpa = r'replace\((.*?)\);'
mres = re.findall(mpa, mhtml.text)

# 關鍵的跳轉步驟,這裡不出問題,基本就成功了。
Mheaders["Host"] = "passport.weibo.cn"
self.session.get(eval(mres[0]), headers=Mheaders)
mlogin = self.session.get(eval(mres[0]), headers=Mheaders)
# print(mlogin.status_code)
# 進過幾次 頁面跳轉後,m.weibo.cn 登錄成功,下次測試是否登錄成功
Mheaders["Host"] = "m.weibo.cn"
Set_url = "https://m.weibo.cn"
pro = self.session.get(Set_url, headers=Mheaders)
pa_login = r'isLogin":true,'
login_res = re.findall(pa_login, pro.text)
# print(login_res)

# 可以通過 session.cookies 對 cookies 進行下一步相關操作
self.session.cookies.save()
# print("*"*50)
# print(self.cookie_path)

 

第五步:定義cookie的載入和信息的重定義

def get_cookies():
# 載入cookie
cookies = cookielib.LWPCookieJar("Cookie.txt")
cookies.load(ignore_discard=True, ignore_expires=True)
# 將cookie轉換成字典
cookie_dict = requests.utils.dict_from_cookiejar(cookies)
return cookie_dict

def info_parser(data):
id,time,text = data['id'],data['created_at'],data['text']
user = data['user']
uid,username,following,followed,gender = \
user['id'],user['screen_name'],user['follow_count'],user['followers_count'],user['gender']
return {
'wid':id,
'time':time,
'text':text,
'uid':uid,
'username':username,
'following':following,
'followed':followed,
'gender':gender
}

 

第六步:開始爬

def start_crawl(cookie_dict,id):
base_url = 'https://m.weibo.cn/comments/hotflow?id={}&mid={}&max_id_type=0'
next_url = 'https://m.weibo.cn/comments/hotflow?id={}&mid={}&max_id={}&max_id_type={}'
page = 1
id_type = 0
comment_count = 0
requests_count = 1
res = requests.get(url=base_url.format(id,id), headers=headers,cookies=cookie_dict)
while True:
print('parse page {}'.format(page))
page += 1
try:
data = res.json()['data']
wdata = []
max_id = data['max_id']
for c in data['data']:
comment_count += 1
row = info_parser(c)
wdata.append(info_parser(c))
if c.get('comments', None):
temp = []
for cc in c.get('comments'):
temp.append(info_parser(cc))
wdata.append(info_parser(cc))
comment_count += 1
row['comments'] = temp
print(row)
with open('{}/{}.csv'.format(comment_path, id), mode='a+', encoding='utf-8-sig', newline='') as f:
writer = csv.writer(f)
for d in wdata:
writer.writerow([d['wid'],d['time'],d['text'],d['uid'],d['username'],d['following'],d['followed'],d['gender']])

time.sleep(3)
except:
print(res.text)
id_type += 1
print('評論總數: {}'.format(comment_count))

res = requests.get(url=next_url.format(id, id, max_id,id_type), headers=headers,cookies=cookie_dict)
requests_count += 1
if requests_count%50==0:
print(id_type)
print(res.status_code)

 

第七步:主函數

if __name__ == '__main__':
username = "18100000000" # 用戶名(註冊的手機號)
password = "123456" # 密碼
cookie_path = "Cookie.txt" # 保存cookie 的文件名稱
id = '4477416430959369' # 爬取微博的 id
WeiboLogin(username, password, cookie_path).login()
with open('{}/{}.csv'.format(comment_path, id), mode='w', encoding='utf-8-sig', newline='') as f:
writer = csv.writer(f)
writer.writerow(['wid', 'time', 'text', 'uid', 'username', 'following', 'followed', 'gender'])
start_crawl(get_cookies(), id)

 

第八步:獲取id

  • 你需要獲得想要找的微博id,那麼對於小白來說怎麼找id呢?
  • 首先找到你想爬的微博,這裡以微博故事為例,在瀏覽器內按下F12,並且點擊評論按鈕

                                                     

  • 點擊‘網路’,找到一條像圖中的get請求。查看它的參數,mid就是它的id

 

 

全文代碼

為了方便大家拿去練習,以下是上文的全部代碼整合!

import time
import base64
import rsa
import binascii
import requests
import re
from PIL import Image
import random
from urllib.parse import quote_plus
import http.cookiejar as cookielib
import csv
import os
comment_path = 'comment'
if not os.path.exists(comment_path):
os.mkdir(comment_path)

agent = 'mozilla/5.0 (windowS NT 10.0; win64; x64) appLewEbkit/537.36 (KHTML, likE gecko) chrome/71.0.3578.98 safari/537.36'
headers = {'User-Agent': agent}

class WeiboLogin(object):
"""
通過登錄 weibo.com 然後跳轉到 m.weibo.cn
"""

# 初始化數據
def __init__(self, user, password, cookie_path):
super(WeiboLogin, self).__init__()
self.user = user
self.password = password
self.session = requests.Session()
self.cookie_path = cookie_path
# LWPCookieJar是python中管理cookie的工具,可以將cookie保存到文件,或者在文件中讀取cookie數據到程式
self.session.cookies = cookielib.LWPCookieJar(filename=self.cookie_path)
self.index_url = "http://weibo.com/login.php"
self.session.get(self.index_url, headers=headers, timeout=2)
self.postdata = dict()

def get_su(self):
"""
對 email 地址和手機號碼 先 javascript 中 encodeURIComponent
對應 Python 3 中的是 urllib.parse.quote_plus
然後在 base64 加密後decode
"""
username_quote = quote_plus(self.user)
username_base64 = base64.b64encode(username_quote.encode("utf-8"))
return username_base64.decode("utf-8")

# 預登陸獲得 servertime, nonce, pubkey, rsakv
def get_server_data(self, su):
"""與原來的相比,微博的登錄從 v1.4.18 升級到了 v1.4.19
這裡使用了 URL 拼接的方式,也可以用 Params 參數傳遞的方式
"""
pre_url = "http://login.sina.com.cn/sso/prelogin.php?entry=weibo&callback=sinaSSOController.preloginCallBack&su="
pre_url = pre_url + su + "&rsakt=mod&checkpin=1&client=ssologin.js(v1.4.19)&_="
pre_url = pre_url + str(int(time.time() * 1000))
pre_data_res = self.session.get(pre_url, headers=headers)
# print("*"*50)
# print(pre_data_res.text)
# print("*" * 50)
sever_data = eval(pre_data_res.content.decode("utf-8").replace("sinaSSOController.preloginCallBack", ''))

return sever_data

def get_password(self, servertime, nonce, pubkey):
"""對密碼進行 RSA 的加密"""
rsaPublickey = int(pubkey, 16)
key = rsa.PublicKey(rsaPublickey, 65537) # 創建公鑰
message = str(servertime) + '\t' + str(nonce) + '\n' + str(self.password) # 拼接明文js加密文件中得到
message = message.encode("utf-8")
passwd = rsa.encrypt(message, key) # 加密
passwd = binascii.b2a_hex(passwd) # 將加密信息轉換為16進位。
return passwd

def get_cha(self, pcid):
"""獲取驗證碼,並且用PIL打開,
1. 如果本機安裝了圖片查看軟體,也可以用 os.subprocess 的打開驗證碼
2. 可以改寫此函數接入打碼平臺。
"""
cha_url = "https://login.sina.com.cn/cgi/pin.php?r="
cha_url = cha_url + str(int(random.random() * 100000000)) + "&s=0&p="
cha_url = cha_url + pcid
cha_page = self.session.get(cha_url, headers=headers)
with open("cha.jpg", 'wb') as f:
f.write(cha_page.content)
f.close()
try:
im = Image.open("cha.jpg")
im.show()
im.close()
except Exception as e:
print(u"請到當前目錄下,找到驗證碼後輸入")

def pre_login(self):
# su 是加密後的用戶名
su = self.get_su()
sever_data = self.get_server_data(su)
servertime = sever_data["servertime"]
nonce = sever_data['nonce']
rsakv = sever_data["rsakv"]
pubkey = sever_data["pubkey"]
showpin = sever_data["showpin"] # 這個參數的意義待探索
password_secret = self.get_password(servertime, nonce, pubkey)

self.postdata = {
'entry': 'weibo',
'gateway': '1',
'from': '',
'savestate': '7',
'useticket': '1',
'pagerefer': "https://passport.weibo.com",
'vsnf': '1',
'su': su,
'service': 'miniblog',
'servertime': servertime,
'nonce': nonce,
'pwencode': 'rsa2',
'rsakv': rsakv,
'sp': password_secret,
'sr': '1366*768',
'encoding': 'UTF-8',
'prelt': '115',
"cdult": "38",
'url': 'http://weibo.com/ajaxlogin.php?framelogin=1&callback=parent.sinaSSOController.feedBackUrlCallBack',
'returntype': 'TEXT' # 這裡是 TEXT 和 META 選擇,具體含義待探索
}
return sever_data

def login(self):
# 先不輸入驗證碼登錄測試
try:
sever_data = self.pre_login()
login_url = 'https://login.sina.com.cn/sso/login.php?client=ssologin.js(v1.4.19)&_'
login_url = login_url + str(time.time() * 1000)
login_page = self.session.post(login_url, data=self.postdata, headers=headers)
ticket_js = login_page.json()
ticket = ticket_js["ticket"]
except Exception as e:
sever_data = self.pre_login()
login_url = 'https://login.sina.com.cn/sso/login.php?client=ssologin.js(v1.4.19)&_'
login_url = login_url + str(time.time() * 1000)
pcid = sever_data["pcid"]
self.get_cha(pcid)
self.postdata['door'] = input(u"請輸入驗證碼")
login_page = self.session.post(login_url, data=self.postdata, headers=headers)
ticket_js = login_page.json()
ticket = ticket_js["ticket"]
# 以下內容是 處理登錄跳轉鏈接
save_pa = r'==-(\d+)-'
ssosavestate = int(re.findall(save_pa, ticket)[0]) + 3600 * 7
jump_ticket_params = {
"callback": "sinaSSOController.callbackLoginStatus",
"ticket": ticket,
"ssosavestate": str(ssosavestate),
"client": "ssologin.js(v1.4.19)",
"_": str(time.time() * 1000),
}
jump_url = "https://passport.weibo.com/wbsso/login"
jump_headers = {
"Host": "passport.weibo.com",
"Referer": "https://weibo.com/",
"User-Agent": headers["User-Agent"]
}
jump_login = self.session.get(jump_url, params=jump_ticket_params, headers=jump_headers)
uuid = jump_login.text

uuid_pa = r'"uniqueid":"(.*?)"'
uuid_res = re.findall(uuid_pa, uuid, re.S)[0]
web_weibo_url = "http://weibo.com/%s/profile?topnav=1&wvr=6&is_all=1" % uuid_res
weibo_page = self.session.get(web_weibo_url, headers=headers)

# print(weibo_page.content.decode("utf-8")

Mheaders = {
"Host": "login.sina.com.cn",
"User-Agent": agent
}

# m.weibo.cn 登錄的 url 拼接
_rand = str(time.time())
mParams = {
"url
              
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 駕車路線 引入插件 AMap.Driving <script type="text/javascript" src="https://webapi.amap.com/maps?v=1.4.15&key=ce3b1a3a7e67fc75810ce1ba1f83c01a&plugin=AMap.Driv ...
  • RXEdior預設會有文件管理功能,但是靈活性需求不大,目前的設想是文件夾不允許修改,只允許增刪改文件。基於這樣的設想,把界面實現成這個效果: 這個功能並不是一個通用功能,並且我們做的代碼,也沒有按照類庫的標準要求,這種編輯功能實現有些複雜,用了大量的js事件,代碼不是很容易讀。後期這個功能可能會有 ...
  • 鷹眼插件 AMap.OverView 預設在地圖右下角顯示縮略圖 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>map</title> <script type="text/javascript" src= ...
  • 開始 今天和大家聊聊AOP:面向切麵編程思想。開始聊之前,先和大家一起從編程思想的發展說起。 編程思想的發展歷程: 1、POP編程 首先,大家應該都知道,什麼是POP編程吧,就是面向過程編程。關於這個編程思想就不做介紹了。 從思維上來講,面向過程更強調細節,忽視了整體性和邊界性。 典型代表是 C/C ...
  • 基礎準備: 8種基本數據類型包括4種整型,2種浮點型,1個字元型,1個布爾型 暫且稱呼為:(4211) 4種整型: byte short int long 2種浮點型:float double 1種字元型:char 1種布爾型:boolean 詳細分析: 基本數據類型和引用數據類型的區別: 基本數據 ...
  • 目的: 寂寞的夜晚總需要精神依托,用Python滋潤疲憊的身心!!! 效果: 實現類 1 from Common import Common 2 import requests 3 4 class Get_mn(Common): 5 """ 6 title:Python爬取成人網站圖片Demo 7 ...
  • 基於S2SH開發房屋租賃管理系統(前臺+後臺)開發環境: Windows操作系統開發工具:Myeclipse+Jdk+Tomcat+MYSQL資料庫運行效果圖 源碼及原文鏈接:https://javadao.xyz/forum.php?mod=viewthread&tid=102 ...
  • 基於S2SH開髮網上蛋糕店(甜品)購物商城系統(前臺+後臺) 開發環境: Windows操作系統開發工具:eclipse+Jdk1.8+Tomcat8+MySQL資料庫註意:請使用JDK1.8 Tomcat8版本運行運行效果圖 源碼及原文鏈接:https://javadao.xyz/forum.ph ...
一周排行
    -Advertisement-
    Play Games
  • 示例項目結構 在 Visual Studio 中創建一個 WinForms 應用程式後,項目結構如下所示: MyWinFormsApp/ │ ├───Properties/ │ └───Settings.settings │ ├───bin/ │ ├───Debug/ │ └───Release/ ...
  • [STAThread] 特性用於需要與 COM 組件交互的應用程式,尤其是依賴單線程模型(如 Windows Forms 應用程式)的組件。在 STA 模式下,線程擁有自己的消息迴圈,這對於處理用戶界面和某些 COM 組件是必要的。 [STAThread] static void Main(stri ...
  • 在WinForm中使用全局異常捕獲處理 在WinForm應用程式中,全局異常捕獲是確保程式穩定性的關鍵。通過在Program類的Main方法中設置全局異常處理,可以有效地捕獲並處理未預見的異常,從而避免程式崩潰。 註冊全局異常事件 [STAThread] static void Main() { / ...
  • 前言 給大家推薦一款開源的 Winform 控制項庫,可以幫助我們開發更加美觀、漂亮的 WinForm 界面。 項目介紹 SunnyUI.NET 是一個基於 .NET Framework 4.0+、.NET 6、.NET 7 和 .NET 8 的 WinForm 開源控制項庫,同時也提供了工具類庫、擴展 ...
  • 說明 該文章是屬於OverallAuth2.0系列文章,每周更新一篇該系列文章(從0到1完成系統開發)。 該系統文章,我會儘量說的非常詳細,做到不管新手、老手都能看懂。 說明:OverallAuth2.0 是一個簡單、易懂、功能強大的許可權+可視化流程管理系統。 有興趣的朋友,請關註我吧(*^▽^*) ...
  • 一、下載安裝 1.下載git 必須先下載並安裝git,再TortoiseGit下載安裝 git安裝參考教程:https://blog.csdn.net/mukes/article/details/115693833 2.TortoiseGit下載與安裝 TortoiseGit,Git客戶端,32/6 ...
  • 前言 在項目開發過程中,理解數據結構和演算法如同掌握蓋房子的秘訣。演算法不僅能幫助我們編寫高效、優質的代碼,還能解決項目中遇到的各種難題。 給大家推薦一個支持C#的開源免費、新手友好的數據結構與演算法入門教程:Hello演算法。 項目介紹 《Hello Algo》是一本開源免費、新手友好的數據結構與演算法入門 ...
  • 1.生成單個Proto.bat內容 @rem Copyright 2016, Google Inc. @rem All rights reserved. @rem @rem Redistribution and use in source and binary forms, with or with ...
  • 一:背景 1. 講故事 前段時間有位朋友找到我,說他的窗體程式在客戶這邊出現了卡死,讓我幫忙看下怎麼回事?dump也生成了,既然有dump了那就上 windbg 分析吧。 二:WinDbg 分析 1. 為什麼會卡死 窗體程式的卡死,入口門檻很低,後續往下分析就不一定了,不管怎麼說先用 !clrsta ...
  • 前言 人工智慧時代,人臉識別技術已成為安全驗證、身份識別和用戶交互的關鍵工具。 給大家推薦一款.NET 開源提供了強大的人臉識別 API,工具不僅易於集成,還具備高效處理能力。 本文將介紹一款如何利用這些API,為我們的項目添加智能識別的亮點。 項目介紹 GitHub 上擁有 1.2k 星標的 C# ...