在豆瓣上帮小姐姐的租房帖顶帖。
顶帖不易,于是想到用python调用接口自动顶帖。
通过分析网络接口数据抓到豆瓣上[发表评论]的接口为
其中xxxxx 为小组里所发帖子的唯一ID,位置如下
有了第一步,就开始写代码。引入python的requests库轻松就调用成功了。
很顺利的过程。
写成定时任务,通过schedule模块定时30秒刷一个。
很顺利的过程+1。
没运行多久就出现了问题,接口返回200。 去看了看页面,原来是有个验证码需要验证。
不过这也难不到我们不是,为了给小姐姐顶帖只能迎难而上。
鄙人观察了一下验证码都是英文字母,这里介绍一个验证码试别工具:百度的文字识别API。
具体代码后面贴出。这里不详细叙述。传入的是一张图片流,输出的是这张图片里所含的文字信息。(这里文字信息泛指一切符号,不要想得很美好,都是英文字母返回,后面使用的时候吃过亏)
页面的验证码图片还是通过解析 评论接口 的返回html数据获得。通过简单的正则匹配就可以轻松获得。拿到图片意味着我们可以通过百度文字试别API获取到图片的文字信息了。没错,验证码的参数值搞定了,传入接口,一顿操作后。
很顺利的过程+2。
然而这就完了吗,好景不长,发现虽然能通过验证码评论成功了。但是还是失败率极高。我就想啊,或许是试别的验证码和实际图片里呈现的不符。 打印出图片的URL,肉眼比对和文字识别的结果。 虽然最终证实是不一样的,但是当时没仔细一下子发现,愣是看了很久。原因就是前面的一个伏笔,识别的是文字符号不只是英文,仔细看图片里面黑色的背景或者偏白色的部分会被识别为一个"." 点号或者一个空格。 当时打印了结果但是一个空格且是在单词的结尾无法分辨是否存在,直到出现一个点才看的清楚。尼玛,总算找到原因了,改完继续跑。
很顺利的过程+2.5。
为什么这里是2.5呢,因为又tm好景不长,玩过爬虫的人都会遇到封IP甚至封号的情况,所以在刷了一个下午之后,我就被系统制裁了。
最后我还是解封了,但是最好不要用自己的号去刷,可以申请小号去尝试。
当然最后也帮小姐姐找到租友了。
speak is cheap,show me the code。
所以最后贴上代码。
# encoding: utf-8
import urllib.request
import requests
import time
import schedule
import datetime
import json
from aip import AipOcr
import ssl
import re
from io import BytesIO
# ssl._create_default_https_context = ssl._create_unverified_context # 取消全局验证
verify_IMG_ID = "img_code"
img_url = ""
refer = "https://www.douban.com/group/topic/133599338/?start=0" # 正常访问的refer
def job():
global verify_IMG_ID, img_url, refer
url = "https://www.douban.com/group/topic/133599338/add_comment"
headers = {
"Host": "www.douban.com",
"Referer": refer,
"Cookie": "cookie",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36"
}
current_time = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
params = {
"ck": "jhb4",
"rv_comment": "up " + current_time,
"start": 0,
"img": "(binary)",
"captcha-solution": text_identify(img_url).__str__(), # 验证码的解析文本
"captcha-id": verify_IMG_ID, # 验证码图片ID
"submit_btn": "发送"
}
""" 在豆瓣多次调用评论接口后会返回一个页面,需要输入验证码,从页面里我们解析dom信息拿到验证码图片的URL,然后读取成图片,解析文本"""
response = requests.post(url, headers=headers, allow_redirects=False, data=params, verify=False)
print(response)
if response.__str__().__contains__("200"): ## 需要验证码
searchObj = re.search(r'(.*)(https://www.douban.com/misc/captcha)(.*?)(alt="captcha").*',
response.content.__str__(), re.M | re.I)
img_url = searchObj.group(2) + searchObj.group(3) # 图片URL
print("imgURL->" + img_url)
verify_IMG_ID = searchObj.group(3)[4:4 + 27]
print("imgCode->" + verify_IMG_ID)
refer = "https://www.douban.com/group/topic/133599338/add_comment" # 在需要验证码的时候接口的refer也变了
def text_identify(img_url):
if img_url == '':
return ""
APP_ID = 'APP_ID'
API_KEY = 'API_KEY'
SECRET_KEY = 'SECRET_KEY'
client = AipOcr(APP_ID, API_KEY, SECRET_KEY)
# 本地读取图片
def get_file_content(file_path):
with open(file_path, 'rb') as fp:
return fp.read() # 返回字节流
# image = get_file_content(u'C:UsersPCPicturestextimg.png')
# 网络获取图片
res = requests.get(img_url,
stream=True) # 获取字节流最好加stream这个参数,原因见requests官方文档
image = BytesIO(res.content).getvalue()
"""BaiduAPI文字试别"""
result = client.basicAccurate(image)
if "error_msg" in result.keys():
print("图片解析错误:"+result['error_msg'])
return ""
print("BaiduAPI result>>" + str(result)) #调试
if int(result['words_result_num']):
text_plain = result["words_result"][0]["words"].strip().replace(".","")
print("试别结果:%s" % text_plain)
return text_plain # 发现有"点号"或者"空格"被试别
print("未试别:%s" % json.dumps(result))
if __name__ == '__main__':
print("豆瓣刷评开始---")
job()
schedule.every(30).seconds.do(job) #每隔30秒刷一次
while True:
schedule.run_pending()
time.sleep(1)