前些天面试某司让写个爬虫,刚好之前就准备用 Scrapy 框架写个爬虫玩玩的,于是拿乌云的公开漏洞列表练了练手。
源码见 https://github.com/borghan/wyspider

7DD41886-872E-467B-88D7-D307EEAA0309.png

这个爬虫除了 Scrapy 自带的一些设置,还加入了 Keywords 和 Random User Agent 功能(然并卵)。
做了些简单的统计(typecho 1.0 的后台 markdown 居然不支持表格,只好贴图了):

QQ20151008-3@2x.png
QQ20151008-1@2x.png
QQ20151008-2@2x.png

以下是开发中的遇到的一些问题:

照着 Scrapy 的官方文档 写个小爬虫很简单,难点主要在解析页面元素和把结果存进数据库。乌云漏洞详情页面有些地方空格和制表符混杂,有些元素没有 class 或者 id 标识,对爬虫太不友好…… (后来发现乌云手机版的页面写的很规范,所以爬手机版的数据会方便很多)

至于存进数据库,刚开始参考这篇文章—— scrapy爬虫成长日记之将抓取内容写入mysql数据库,但是在操作中总是报 Mysql 的语法错误。我一直用 print 来 debug 程序,遇到这种问题想打印出有错误的 SQL 语句纠结了半天。最后查到类似的问题 Print the actual query MySQLdb runs,用 print(conn._last_executed) 即可。

观察错误的 SQL 语句发现执行的语句形似

INSERT INTO bugs(title,corp,detail) VALUES((111),(222),(333,444))

所以如果 item['title'] = [u'111'] (用 xpath 解析得到的都是一个 list,里面是 unicode 字符串),插入数据库时就变成了带括号的 (111)。而向 detail 字段一次性插入两个值 (333,444) 当然会报错。

最大的坑就是 xpath 解析 dom 元素时,如果遇到了换行 <br>,就会生成一个新的 value。比如有个 div 里是这样的:

<div id="test">
    <p>333<br>444</p>
</div>

item['test'] = response.xpath('//div[@id="test"]/p/text()').extract() 得到的不是 [u'333444'] 而是 [u'333', u'444']。

折腾到最后我决定把所有的 list 都转换成字符串……

for x in item:
    if bool(item[x]):
        item[x] = ''.join(item[x]).strip()
    else:
        item[x] = None

还有个小坑是在 Mysql 中的 timestamp 类型虽然默认值是 '0000-00-00 00:00:00',但是如果给它的值为 NULL 的话,实际上会显示的值是 CURRENT_TIMESTAMP,即当前的时间。所以给它一个值 '0' 才会显示 '0000-00-00 00:00:00'。


最后写完了才发现通过 http://www.wooyun.org/bug.php?action=view&id=100000 里的 id 可以遍历漏洞信息…… Orz