Scrapy使用以及Xpath的一些坑, 再入剁手
scrapy爬虫: https:www.scrapy.org
本篇博客依托的项目: https://github.com/viciousstar/BitcointalkSpider/
一. Scrapy
- 各种依赖库的安装请提前参考官方文档 http://doc.scrapy.org/en/0.24/intro/install.html, 另外python-dev完整的开发库最好安装, 可以避免很多不知所以然的问题.
- 如果看英文文档有困难, 可以先参看一下scrapy中文翻译项目 http://scrapy-chs.readthedocs.org/zh_CN/latest/
- scrapy.contrib.spiders.Rule中的一些提取规则是以正则表达式形式写出, 注意网站中的". ?"等符号要进行转义. eg.
-
Rule(LinkExtractor(allow = ("https://bitcointalk\.org/index\.php\?board=\d+\.\d+", ) ) )
二. scrapy 调试
scrapy本身提供了很好用的交互式调试命令,可以方便调试爬虫的各种功能。
- 命令格式:scrapy shell url
- 注意事项:
- shell 命令可以需要project,也可以不需要project,当然我们调试的时候如果不是刚刚使用scrapy,肯定是为了调试自己project中的某个功能,这是就需要你在你的project目录下使用此命令,如果你的url符合当前project的domin,scrapy会自动调用你的spider,此时的交互式python命令行下的全局变量spider就是你自己编写的spider。
- 因为scrapy shell 命令是在iinux下的命令,如果网址中包括比较特殊的符号,记得进行转义,比如 “&” 符号。
- 进入python交互命令中,可以用dir(spider),查看spider中的各种属性,这其中就包括了你自己定义的提取函数,规则等等。
- 注意利用view(response)在浏览器中观察爬虫看到的网页是否和我们看到的网页一样,其实大部分都是不相同的。
- 未完待续。。。 (有时间会写一篇详细的图文调试过程)
三. 动态网页爬取的一点,动态url的处理
在爬取 https://bitsharestalk.org 的时候,发现网站会为每一个url增加一个sessionid属性,可能是为了标记用户访问历史,而且这个seesionid随着每次访问都会动态变化,这就为爬虫的去重处理(即标记已经爬取过的网站)和提取规则增加了难度。
比如https://bitsharestalk.org/index.php?board=5.0 会变成 https://bitsharestalk.org/index.phpPHPSESSID=9771d42640ab3c89eb77e8bd9e220b53&board=5.0,下面介绍集中处理方法
- 仅适用你的爬虫使用的是scrapy.contrib.spiders.CrawlSpider, 在这个内置爬虫中,你提取url要通过Rule类来进行提取,其自带了对提取后的url进行加工的函数。
Rule(LinkExtractor(allow = ("https://bitsharestalk\.org/index\.php\?PHPSESSID\S*board=\d+\.\d+$", "https://bitsharestalk\.org/index\.php\?board=\d+\.\d+$")), process_links = 'link_filtering'), #默认函数process_links
Rule(LinkExtractor(allow = ("https://bitsharestalk\.org/index\.php\?PHPSESSID\S*topic=\d+\.\d+$", "https://bitsharestalk\.org/index\.php\?topic=\d+\.\d+$", ),),
callback = "extractPost",
follow = True, process_links = 'link_filtering'),
Rule(LinkExtractor(allow = ("https://bitsharestalk\.org/index\.php\?PHPSESSID\S*action=profile;u=\d+$", "https://bitsharestalk\.org/index\.php\?action=profile;u=\d+$", ),),
callback = "extractUser", process_links = 'link_filtering')
)
def link_filtering(self, links):
ret = []
for link in links:
url = link.url
#print "This is the yuanlai ", link.url
urlfirst, urllast = url.split("?")
if urllast:
link.url = urlfirst + "?" + urllast.split("&", 1)[1]
#print link.url
return links
link_filtering()函数对url进行了处理,过滤掉了sessid,关于Rule类的process_links函数和links类,官方文档中并没有给出介绍,给出一个参考 https://groups.google.com/forum/#!topic/scrapy-users/RHGtm_2GO1M(也许需要梯子,你懂得)
如果你是自己实现的爬虫,那么url的处理更是可定制的,只需要自己处理一下就可以了。
2. 通用方法,修改scrapy的去重策略,直接用自己的算法替代内置算法。或者编写自己的scheduler中间件,这一部分笔者没有亲自实现,应该是版本更新,
scrapy这方面有改动,读者可以自行探索。参考连接: http://blog.pluskid.org/?p=381
四. Xpath--大多是scrapy response 自集成的xpath特性
- 传送门 http://www.w3.org/TR/xpath20/
- 在使用chrome等浏览器自带的提取extract xpath路径的时候, 通常现在的浏览器都会对html文本进行一定的规范化, 导致明明在浏览器中提取正确, 却在程序中返回错误的结果,比如
-
<table cellpadding="0" cellspacing="0" border="0" style="margin-left: 10px;">
<tbody>
some others
</tbody>
</table>浏览器会在table标签下添加tbody
- 目前本人还没有什么好的解决方法, 暂时的解决方案是, 多用相对路径或者是属性标签等定位而不依赖于绝对路径, 如果非要使用绝对路径的方法:
- scrapy shell somepage
- view(response)
- 然后再开发者工具中看的路径就是原始路径
- xpath方法extract()返回的都是unicode字符串, 要注意对其进行的操作, 以及适时转化为字符串形式(通常情况下函数会自动帮助你转换, 如果可以转换的话), 尤其是在一起使用正则表达式的时候会产生命名规则正确却匹配不到的情况.
- 如果在某个xpath对象下继续使用xpath规则提取, 当提取某个对象下的所有某个对象所有tr标签.
-
html = response.xpath("/html/body")
tr = html.xpath(".//tr") #搜索body下的所有tr必须加上'.', 否则搜索的是整个文档的所有tr
五. unicode导入到json文件
使用下载器中间件即可,详情参考代码吧。(有时间详细补充)
ps: 吐槽一下排版,博客排版一直没找到什么好的工具,只能在网页版排了,不知道各位能不能推荐一下 -_-||, 拒绝任何形式的转载。