写在前面
这两天本打算做两件事,其一是仅利用BDUSS实现模拟登录百度,再进一步请求到贴吧首页,其二是关于朴素贝叶斯分类器的,拉普拉斯平滑是很重要的内容,需要对文章进行补充。但第一件事就花了两天,而且得到的结果与预期并不相符,暂且记录一下过程。拉普拉斯平滑近期会补充。
思路分析
前几天写了贴吧自动灌水脚本,是用完整的cookie请求的,而我想用最少的信息做成这件事,把cookie精简再精简,是否可以只利用某一字段就实现呢?目前未探究这个问题,而选择了另外一个方向,我尝试使用Cookie中的BDUSS字段请求贴吧首页,并不能返回登录状态的信息,退而求其次,请求百度首页,这一次在返回的信息中找到了用户名,也就是说,登录成功了。
接下来打开开发者工具,把网页从百度首页转向贴吧首页,可以看到有三次302重定向,重定向的过程中生成了一个贴吧需要的“令牌”,将其写进了贴吧cookie中,这个“令牌”是STOKEN字段,用包含BDUSS和STOKEN两个字段的cookie重新请求贴吧首页,登录成功,返回的信息中有我关注的贴吧。
那这个STOKEN字段是怎么生成的呢?使用浏览器登录百度(非贴吧首页)的时候,百度会把请求发送到passport.baidu.com,即百度的账号中心,它会生成PTOKEN和STOKEN,而获取STOKEN的关键就是PTOKEN,我猜PTOKEN是md5加密的32位小写密文,明文的规则没有在百度的js文件中找到,这种东西应该被不起眼的变量名伪装保护了。好了,啰里啰嗦一大段,并没有图片可以放上来....
主要代码
用到的包和全局变量
#用到的包
import requests
import time
from bs4 import BeautifulSoup as bs
import logging
#日志相关
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
logger = logging.getLogger(__name__)
#请求头
headers_sign = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.66 Safari/537.36",
}
#从这个接口中获取关注的吧
Attention_URL = "http://tieba.baidu.com/f/like/mylike"
#利用此接口进行签到
sign_url = 'https://tieba.baidu.com/sign/add'
登录模块
def login():
#贴吧首页
url = "https://tieba.baidu.com/index.html"
#在这里写上你的BDUSS
BDUSS = [
"",
]
#在这里写上PTOKEN
PTOKEN = [
""
]
#构建Cookie
login_cookie = {
"BDUSS": BDUSS[0],
"PTOKEN": PTOKEN[0],
}
#向贴吧首页发起GET请求,并禁止重定向
req = requests.get(url = url,headers = headers_sign,cookies = login_cookie,allow_redirects = False)
#从反馈的信息中对Cookie进行补齐
for key in req.cookies.keys():
login_cookie[key] = req.cookies[key]
#虽然上面禁止了重定向,但是status_code仍然是302,如果是200那说明BDUSS过期了
if req.status_code == 302:
#重定向的目标地址
pass_url = req.headers['Location']
#print(pass_url) #可以取消注释看看重定向的地址
#对目标地址发起请求,这里仍然会重定向
req_pass = requests.get(url = pass_url,headers = headers_sign,cookies = login_cookie,allow_redirects = False)
#获取重定向的地址
stoken_url = req_pass.headers['Location']
#print(stoken_url)
#访问目标地址,获取STOKEN
req_stoken = requests.get(url = stoken_url,headers = headers_sign,cookies = login_cookie,allow_redirects = False)
try:
#将STOKEN写入login_cookie
login_cookie["STOKEN"] = req_stoken.cookies['STOKEN']
#print(login_cookie['STOKEN'])
#带上login_cookie去签到
run(login_cookie)
except:
pass
else:
print(req.status_code)
其他函数
#签到模块
def client_sign(kw,Cookie):
#post请求需要的参数,kw指吧名
data = {"ie":"utf-8","kw":kw}
#带上参数对接口发起post请求,并将response处理成json格式
res = requests.post(url=sign_url, data=data, cookies = Cookie,timeout=5).json()
#检查签到状态
if res['no'] == 0:
logger.info(kw + ',' + '签到成功!')
else:
logger.info(kw + ',' + res['error'])
#获取关注的吧
def get_favorite(Cookie):
#Attention_URL算是一个接口,在i贴吧查看关注的吧时可以看到
req = requests.get(url = Attention_URL,headers=headers_sign,cookies = Cookie)
#调用bs4解析网页,需要预先安装lxml模块
html = bs(req.text,'lxml')
#从网页中检索关注的吧
tieba_lists = html.find('div',class_ = "forum_table").find_all("tr")[1:]
#将关注的吧存入列表并返回
myfavorite = []
for tieba in tieba_lists:
myfavorite.append(tieba.find('a',class_ = None).get('title'))
return myfavorite
#控制函数
def run(Cookie):
#获取关注的吧
favorites = get_favorite(Cookie)
#逐一签到,并停顿0.1秒
for favorite in favorites:
client_sign(favorite,Cookie)
time.sleep(0.1)
入口函数
if __name__ == '__main__':
login()
信息获取
关于BDUSS和PTOKEN的获取,首先打开Chrome,清理掉baidu.com下的所有cookie,重新登录百度。转到谷歌设置-隐私设置和安全性-cookie及其他网站数据-查看所有cookie和网站数据,分别检索passport.baidu.com和baidu.com,可以找到PTOKEN,STOKEN以及BDUSS。也可以从开发者工具里面获取,但是获取PTOKEN需要请求一次贴吧首页,从重定向的地址里面找。
经过多次尝试,我觉得STOKEN是由PTOKEN和BDUSS共同决定的,后面两者不变它就不变。BDUSS是根据用户信息得到的,这个算是用户标识符,虽然它也是可变的,但只要不退出登录,很久都不会过期。PTOKEN也是可变的,跟BDUSS一样,退出登录的时候就会过期,所谓退出登录是指在百度首页点击退出登录按钮,或者使用以下方法:
#参数提供BDUSS就可以了
def logout(bduss = None):
if bduss:
cookie = {'BDUSS':bduss}
url = 'https://passport.baidu.com/?logout&u='
requests.post(url = url,headers = headers_sign,cookies = cookie)
print('该BDUSS已作废')
写在后面
如果能找到PTOKEN的生成规则我会再来更新的!
第一次更新
对单独贴吧签到的话,只需要BDUSS就够了,获取关注的吧还是需要STOKEN
import requests
headers_sign = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.66 Safari/537.36",
}
sign_url = 'https://tieba.baidu.com/sign/add'
def client_sign(kw,Cookie):
data = {"ie":"utf-8","kw":kw}
res = requests.post(url=sign_url, data=data, cookies = Cookie,timeout=5).json()
if res['no'] == 0:
print(kw + ',' + '签到成功!')
else:
print(kw + ',' + res['error'])
if __name__ == '__main__':
kw = ''#吧名
Cookie = {'BDUSS':''} #写入你的BDUSS
client_sign(kw,Cookie)