Scrapy使用笔记-如何写爬虫脚本进行网页文本挖掘采集需要的数据
Comment因为课题需求,需要从网站上挖掘一些有用的数据以构建模型。网站虽然提供整合的数据库,但每条数据只给了网址链接,自己从中找具体的数据内容。
网页文本挖掘其实并不是什么新鲜事儿,记得高中的时候就尝试通过“寻找规律法”从网页中获取自己想要的数据,当初还用的是Visual Basic。到了大学,学了一段时间的PHP,并没有用此自己做网页,倒是从中学习了如何用PHP采集门户网站的信息。 这些方法基本都是同样的原理,根据某信息前后数据比如<div class=”content”><span>我需要的</span>…</div>,那么采集这个数据只需要确定网站只有一个class=content的层,这样寻找到<div class=”content”><span>的位置,以及该位置后第一个出现</span>的位置,那么当中这些信息就是我所需要的。
这种方法虽然简单实用,但是碰到稍微复杂的情况,比如网站不止一个content,亦或是<span>里面万一夹杂着参数可变的attributes,那么采集起来就不那么容易了。
自从开始用了Python,就对其爱不释手,除了因为其语言简洁,还有就是有太多优秀的“小程序”(或者说Package)由Python开发,方便引用并开发。用Python写爬虫脚本,相信已经有不少优秀的程序,我找到了俩, Scrapy 与 Pyspider 。感觉前者倾向于一次性的爬虫,轻量级,可扩展性强。后者更倾向是采集服务器。根据不同的需求可以选择不同的工具,两者的挖掘规律虽有不同,但也大同小异。由于我仅仅是需要一次性得到已知网址的所有需要的信息,所以我选择了Scrapy,下面是我的使用笔记。
安装:
解析框架:
import scrapyclass BlogSpider(scrapy.Spider):
name = ‘blogspider’
start_urls = [‘http://blog.scrapinghub.com']def parse(self, response):
for url in response.css(‘ul li a::attr(“href”)’).re(r’.*/\d\d\d\d/\d\d/$’):
yield scrapy.Request(response.urljoin(url), self.parse_titles)def parse_titles(self, response):
for post_title in response.css(‘div.entries > ul > li a::text’).extract():
yield {‘title’: post_title}
可见所谓规则是一个继承的类,最重要的类成员就是start_urls,它是个list,决定了最初要挖掘哪些网页。python脚本一个好处是容易“扩展”,在这里你可以直接使用with open来打开一个文件获取url赋值给start_urls。
最重要的方法就是parse,它相当于是一个回调函数,当系统读取start_urls里面的网址的内容后,则会调用这个函数进行解析。如果要解析的网页里包含你想要进一步解析的链接(比如采集一个博客,先要采集它的文章列表,然后进一步解析文章列表里的每个链接对应的网站),那么可以用yield scrapy.Request(url, anther callback function),用另一个回调函数来解析那个具体的文章页面。当然,一般链接用的都是相对路径,所以scrapy也给了response.urljoin函数来解决这个问题。
有经验的人不难发现,采集离不开这几个关键点,初始网址用以解析“文章列表”,然后通过链接每个文章,进一步解析“文章内容”。具体在这两个回调函数里写规则
解析规则:
不难发现,每个回调函数的参数是response,可以理解为整个网页的源代码,当然已经封装成了一个对象,我们可以直接调用css,xpath两种方法进行解析。css与xpath都可以解析,规则差不多,看个人爱好。首页给的是css例子,我这里介绍下xpath。
如果我要挖取<..很多级…><div class=”content”><span>my word</span></div><…..>
那么只要response.xpath(‘//div[@class=”content”][1]/span/text()’).extract()就能得到一个list,内容是[‘my word’]
解释下这句话的意思
//
越级寻找,在本例中,无论div前面被多少个标签包裹,只要是符合条件的div都找到
div[…]
寻找符合条件的div标签,“
[@class=”content]
@表示标签属性,即这个div的class内容为”content”,双引号是需要的,(通常html里都用双引号,所以我们在写规则的时候用单引号表示字符串,原因的话,熟悉Python肯定得知道吧~~
[1]
上面虽没,但很重要,表示第一个符合条件的标签,条件可以叠加,比如[@class=”content”][1],不过这可能会产生误区,详情点这里看
官方文档
介绍
/
下一级寻找,也就是说span必须在前面找到的div的下一级,否则无效
text()
标签里面的文本
xpath函数得到的是selector列表,我们可以对这个进一步用xpath,而如果要获得最终我们要的数据,则最终要用
extract()
函数。
由于我的例子中符合条件的只有一个my word,所以最终生成单值列表。而如果符合条件的不知一个比如:
<div class=”content”><span>1</span><span>2</span></div><div class=”content”><span>3</span><span>4</span></div>
那么1、2、3、4都会在list里。如果有一个条件不符合,比如class不对,或者span不在div的下一级而是下两级,那么就不会有。