前言
文章起源于自己的一个需求:想要删除掉自己的若干个小号在豆瓣小组上的发帖及回复记录。这是一件看似简单的事情,但是一遍一遍的重复操作实在让我感到非常绝望,特别是删除自己的回复时,有时候回复的帖子的回复有好几十页,得一页一页的翻。于是就想到用脚本来代替人力操作。对于一名职业为前端工程师的人而言,最容易想到的方法就是打开DevTools发个Ajax请求直接搞定了。不过经历过几次之后发现这种方法很难沉淀下来,于是就想能不能写到脚本里面。一开始依旧想到的是用NodeJS来实现,但是由于最近由于接触程序化交易比较多,发现如果再不温习一下Python大蟒蛇又要忘光了,于是就想借机同时练练Python。
结果
先说结果
安装
两种方式:
- 源代码已放到github,可自行查看下载:https://github.com/acrazing/dbapi
git clone https://github.com/acrazing/dbapi.git
cd dbapi
# 安装依赖
pip install -r requirements.txt
- 包已发布到pip,可自行安装:
pip install dbapi
使用
首先得安装,然后:
- 登录客户端:因为客户端有缓存Session,所以你只需要登录一次,在命令行中:
python -m dbapi.DoubanAPI test_client login "username" "password"
- 删除自己回复过的帖子:因为要删除自己发的帖子实际上是要删除掉所有自己在帖子下的回复,如果回复非常多不知道自己回复的在哪一页或者自己的回复非常多,操作起来会比较恶心
python -m dbapi.DoubanAPI test_api remove_commented_topic "topic_id" # topic_id 可以通过下面这个命令拿到: python -m dbapi.DoubanAPI test_api list_commented_topics # 这个命令会返回所有自己回复过的帖子
- 删除自己发的帖子:因为要先删除所有的回复,所以也很恶心
python -m dbapi.DoubanAPI test_api remove_topic "topic_id" # topic_id 可以通过下面这个命令拿到: python -m dbapi.DoubanAPI test_api list_user_topics # 这个命令会返回所有自己发布的帖子
需求分析
- 首先需求很明确:快速删除掉在豆瓣小组内的发帖和回复记录
- 要访问自己的豆瓣小组,需要登录帐号获取会话信息,其中一个关键的信息会话ID
dbcl2
设置了HttpOnly
,此外还需要一个动态idck
。当然这些问题都可以通过把所有的Cookie
添加到客户端搞定。 - 要删除发帖记录,需要先删除掉贴子下的所有回复,在删除别人的回复时,需要调用管理员权限并提交理由
- 要删除掉回复记录,需要删除掉所有的自己的回复,但是别人的引用是无法删除的,所以最后要真正隐藏掉记录,需要注销帐号。
- 登录是敏感操作,频繁登录很容易触发机器人,需要缓存会话信息
- 访问频率过高也会触发机器人,需要做访问限制
接口列表
通过浏览器抓包发现,相关操作主要有几下几个接口:
- 登录账号:
POST https://www.douban.com/accounts/login
,登录前需要先获取bid
等信息,登录时如果不设置redir_url
,会自动跳转到豆瓣首页,如果登录失败,则不会跳转,可以据此判断登录是否成功,或者也可以用Cookie信息进行判断。跳转完成后会拿到所有会话所需要的Cookie信息,所以需要跟踪跳转 - 登出账号:
GET https://www.douban.com/accounts/logout?source=group&ck=%s
,这里的ck
就是会话中的ck
- 获取自己发的帖子列表:
GET https://www.douban.com/group/people/%s/publish
,有翻页 - 获取自己回复过的帖子列表:
GET https://www.douban.com/group/people/%s/reply
,有翻页 - 删除自己的回复:
POST https://www.douban.com/j/group/topic/%s/remove_comment
- 删除自己发的帖子下的别人的回复:
POST https://www.douban.com/group/topic/%s/remove_comment
此外还有一些已实现但是与此无关的接口,可以到代码中dbapi/endpoints.py
中查看
接口设计
- 为了方便扩展,封装了一层基础的API SDK:只是对单个页面进行请求及信息提取,所有的其它上层操作都基于这个SDK,比如删除发帖记录等
- 为了方便扩展,对接口进行了模块化处理:比如豆瓣小组
Group
,用户People
等模块等 - 为了方便调用,封装了一个统一的出口类
DoubanAPI
,对会话缓存,登录登出等操作进行统一管理,并引入了各个模块 - 对于每个网络请求,需要用到公共头及会话信息,所以封装了一个基类
BaseAPI
统一网络请求,并且返回数据有可能是html
或者json
,所以提供了三个相关接口,同时部分接口需要显式调用ck
,所以提供了相关接口
依赖
- 网络请求由
requests
实现 - 大部分
read
接口返回的数据都是html
格式,这里使用lxml
及xpath
进行读取 - 使用
logging
输出日志
代码分析
略,请参考源代码
其它
除了小组相关API外,还实现了用户People
相关的部分API,可以实现获取用户profile,关注用户及关注者,代码在dbapi/People.py
中。利用这几个API设计了一个多线程爬虫,用来爬取豆瓣上的热门用户,代码在test/relation.py
中,爬取的结果放在__relation__.json
中。目前我注册了4个豆瓣账号,开了4个线程进行爬取。最开始由一个种子用户sevear
,爬取其关注的用户中关注者大于100
的用户,然后逐渐将关注者最小值加到现在的10000
。目前已发布到Github的结果中,已经爬取了33599
个用户,其中1069
个用户的关注者超过了10000
。发现了一些比较有趣用户,比如熊阿姨
等;也发现热门的用户大多都会贴上自己的微信公众号,微博等信息;还有很多从05年就开始使用豆瓣的重度用户,也有很多注销了的账号。虽然我也很多年前就注册了豆瓣,但是一直没有发现除了发租房贴,看电影评价,听FM(现在已经不用了)之外还有什么其它价值。也许这些人可以给我答案。
总结
- 因为之前对Python的了解仅限于语法层面,未接触过相应的生态,比如pip包管理,
setuptools
等,并且不熟悉相关的基础包。所以几乎得从零开始,是件很头疼的事情,所幸的是Python的包都比较有名气,包管理等网络上也有很多教程,查找起来都比较容易。感谢互联网~ - 通过
test/relation.py
测试发现,目前存在内存泄漏问题,但是捣鼓了半天没有查到问题所在,已经没有兴趣继续花时间了~ - 同上,访问频率过高有可能会触发IP封禁,出现
Please try later
以及检测到你的IP有非正常请求发出balabala
提示~ - 同上,现在4个线程中每个请求之前间隔时间调整到了3秒,再也没有出现IP封禁的提示~
- 客户端架构存在很大问题:比如无法动态更新会话信息,频繁获取模块有额外的性能开销等,需要重新设计整体架构,同样已经没有兴趣了,等以后有心情再更新吧~
- 分不清
账号
和帐号
,帖子
和贴子
,求语文老师