我的个人微博早前有大量跟好友的页面聊天数据,随着时间增多,发的微博近乎上万条,可是微博本身没有提供数据备份功能,查看了一下API文档,从官方提供的接口取得的数据也只是有限条,无法满足需要,因此萌发了写个爬虫用模拟登录的方式将所有发过的微博抓取下来。

一 、先分析一下微博网页版的结构和流程:

首先是登录,需要用户名、密码、验证码,登录成功后进入个人微博主页,在主页右边有一个年份侧边栏,从这里可以按时间查看所有发过的微博,这就是我主要的抓取对象了,再进一步查看页面结构可知,微博按年月进行数据读取,每一个月的微博有可能为0,也有可能有好几页,每一页需要将页面滚动到底部几次才会完全加载出来。

二、然后准备好工具:

Python 3.6

selenium 3.3.3

火狐浏览器驱动 geckodriver-v0.15.0-win64

三、难点与重点:

1、模拟登录过程

新浪微博的网页版登录过程比起别的有一点小曲折,它需要先输入用户名验证后才会显示验证码,不过既然是用selenium模拟,这些都不是问题。

verifyimg = browser.find_element_by_css_selector("img[node-type='verifycode_image']") //验证码图片
num = 0
while verifyimg.get_attribute('src') == "about:blank":
num = num + 1
if num == 5:
logger.info("验证码无法加载,请重试!")
browser.quit()
return
userInput.click() //模拟点击用户输入框以触发验证码显示
time.sleep(8)
pwInput.click()
time.sleep(5)

模拟登录的重点是对验证码图片进行截图保存,用于后续人工识别输入,这一行代码我花了半天进行文档查询和编写调试,目前是在火狐浏览器上调试成功,但是后面我将驱动换成phantomjs,截取下来的却是整个页面。

verifyimg.screenshot("verifycode.png")

2、用脚本将页面拉到底部读取数据

从selenium官方文档上查到的方法,版本是3.3.3。

browser.execute_script("window.scrollTo(0, document.body.scrollHeight);")

3、判断某个年月的微博是否有下一页

由于为了方便抓取,设置了多个参数,于是为了判断下一页,各种语句调试了一天,才整出下面这段代码:

//pages:要下载的页面数;page:当前第几页;pagecount:总页面数
if (not pages) or (not isinstance(pages[0], int)) or (pages[0] > pagecount) or (pages[0] >= pagecount - page) or (pages[0] <= 0): #不传翻页数或者翻页数参数错误
if page < pagecount:
page = page + 1
getWeiboHtml(datenum, url, count, page)
elif page == pagecount:
logger.info("保存完毕!")
return
elif (pages[0] > 0) and (pages[0] < pagecount - page):
if pages[0] == 1:
logger.info("保存完毕!")
return
else:
page = page + 1
flip = pages[0]-1
getWeiboHtml(datenum, url, count, page, flip)
else:
return

4、获取到第一条微博和最新一条微博的日期

第一条微博日期是通过点击微博主页的时间线,获取网址中的stat_date字段数据。

最新一条微博日期直接就从登录后的微博主页内容字段中解析。

5、日志系统

这次这个爬虫项目,不光学到了selenium的使用,还学到了Python自带的日志系统的使用,受益匪浅。

下面的函数使日志系统从文件里读取配置。

def setup_logging(
default_path='logconfig.json',
default_level=logging.INFO,
env_key='LOG_CFG'):
path = default_path
value = os.getenv(env_key, None)
if value:
path = value
if os.path.exists(path):
with open(path, 'r') as f:
config = json.load(f)
logging.config.dictConfig(config)
else:
logging.basicConfig(level=default_level)

然后在程序中引入日志进行记录:

import logging.config
logger = logging.getLogger(__name__)

6、selenium的安装

装selenium的时候并不顺利,一开始是想用chrome浏览器的,但是下载了chrome的驱动后无法使用,折腾了好久最后改用了火狐。

四、进阶

目前微博是以html文件的形式保存下来了,但是还需要继续编写解析器从html里面提取出结构化的数据,还有区别原创与转发,对表情和图片进行下载等,待以后有时间需要一一进行解决。

目前写的爬虫仅能在自己的机子上以命令行的形式运行,想要给朋友使用都不行,因此还要继续学习Python的打包与界面化。