90行代码爬取我的微博
本文来自 fairjm@iteye 转截请注明出处
这90行代码写了大半年,本来年初就能写好的,结果懒癌发作一病不起,昨天突然惊醒,已经过了半年了,这半年来也没业余好好写代码,发的文章也是划水性质,不能再这么下去了.
初衷其实挺简单的,看自己发了1w+的微博,想着哪天不见了青春的记忆就荡然无存,实在太可惜了,保存到本地方便追溯.
目标是 http://weibo.com/xxxx/profile所有页码的内容.
那要怎么干呢,我们知道微博的异步页面渲染用的是接口返回html数据拼接的方式,一般需要构造请求然后自行拼接html,但一页就要请求两次,而且如何拼接要看js是怎么处理的...
实在是过于麻烦了,还不如自己登上去然后保存一下页面呢.
于是就会有这样的操作:
1.登陆http://weibo.com 2.进入profile页面 3.键盘输入End一次,加载页面 4.再输入End一次,加载页面到这页底部. 5.保存 6.点下一页,回到步骤3.没有下一页就结束
但我有350多页,自己操作一定会手酸,何不让程序帮我们完成?
查阅了一下找到了个工具canopy
,基于Selenium
的F# web UI测试框架.
因为不知道微博做了什么限制,我需要偶尔看一下程序的进度,所以我还是需要界面的,选择了chrome的webdriver(注意需要使用最新版,不然测试插件会无法工作).
接下来我们就只需要略生硬地翻译一下上面的步骤就可以啦.
chromeDir <- @"D:\webdriver\chrome"首先设置一下webdriver所在的目录.
start chrome url "https://weibo.com" waitFor (fun () -> let now = currentUrl() now.Contains("/profile"))
启动chrome,跳转到weibo.com 登陆自己完成,然后点击自己的微博跳转到profile页,上面代码如果不在profile页会进行等待.
press Keys.End
按下end 这边可能需要等待一下加载完毕再按下一个End,要按两次拿取一页完整的页面.
然后得到页面文本~
let getHtml () = let ele = element "html" ele.GetAttribute("outerHTML")
接下去我要获得下一页的地址,查看了下html得到css选择器的写法:
let getNextPageElement () = try Some(element "a.page.next") with _ -> None
... ...(省略文件保存 等等操作)
满心欢喜,写好了,开始运行,看着文件夹下html慢慢增加,还是挺开心的,突然程序停了,看了下浏览器在加载的时候卡住了,刷新了下页面才继续加载.
因为程序判断了End两次只要要能获取到下一页才会继续,网页卡在加载根本没把下一页的按钮渲染出来,自然就不行了.想了想还是应该降低速度,增大end的等待时间以及加上错误重试的功能才比较科学,再完善了一下滚到页底的方式:
let pressToProfileEnd () = let pressIt() = pressEnd() sleep 4 pressEnd() sleep 4 pressEnd() //保险起见 再来一次 sleep 4 pressIt() // try it again let notHasNext = getNextPageElement().IsNone if notHasNext then reload() pressIt()
接下去就看着浏览器慢慢滚动,网页一页页被保存到目标文件了,这年末年初的坑终于也是给填上了,不免松了一口气.
(完整代码见:https://github.com/fairjm/fsharpSnippet/blob/master/WeiboProfileCrawler.fs)
Ps:这90行可是包含了空行和注释~爬点东西工具对了代码也可以像python那么少啊(逃