Some Experiences Of Using Scrapy

转载 2013年12月02日 11:37:58

Some Experiences Of Using Scrapy

Posted@2011-05-28 10 p.m.

Categoriespython ,  scrapy

About Scrapy

Scrapy Tutorial

FAQ That Not Included In Manual

Other Tricks

About Scrapy

Scrapy是一个抓取网站的框架,用户需要做的只是定义抓取网站的spider,并在其中定义抓取的规则,获取需要抓取的数据,Scrapy管理其他复杂的工作,比如并发请求,提取之后的数据保存等。
Scrapy 声称他们“偷取”了Django的灵感,虽然两者的方向怎么都联系不到一起去,但是确实如果对Django有了解,对Scrapy的结构会感到很亲切。 Scrapy也会有项目的概念,一个项目里面可以包含多个抓取蜘蛛(spider),抓取的数据结构定义Items,以及一些配置。
Scrapy抓取的流程:通过spider中的定义需要抓取的网站,并将需要的数据提取到Items里面保存,然后通过管道(pipeline)将Items里面的数据提取,保存到文件或者数据库。

Scrapy Tutorial

首先,新建一个项目叫dmoz:

这里参考Scrapy Tutorial里面的例子做说明,抓取Open directory project(dmoz)上的数据。

scrapy startproject dmoz

将会创建一个叫dmoz的目录,结构如下:

dmoz/
   scrapy.cfg   
   dmoz/
       __init__.py
       items.py
       pipelines.py
       settings.py
       spiders/
           __init__.py
           ...
  • scrapy.cfg: 项目配置文件(基本上让它吧)
  • items.py: 需要提取的数据结构定义文件
  • pipelines.py: 管道定义,用来对items里面提取的数据做进一步处理
  • settings.py: 放一些配置
  • spiders: 放置spider的目录

然后,在items.py里面定义我们要抓取的数据:

from scrapy.item import Item, Field

class DmozItem(Item):
   title = Field()
   link = Field()
   desc = Field()

这里我们需要获取dmoz页面上的标题,链接,描述,所以定义一个对应的items结构,不像Django里面models的定义有那么多种类的Field,这里只有一种就叫Field(),再复杂就是Field可以接受一个default值。

接下来,开始写spider:

spider只是一个继承字scrapy.spider.BaseSpider的Python类,有三个必需的定义的成员

  • name: 名字,这个spider的标识
  • start_urls: 一个url列表,spider从这些网页开始抓取
  • parse(): 一个方法,当start_urls里面的网页抓取下来之后需要调用这个方法解析网页内容,同时需要返回下一个需要抓取的网页,或者返回items列表(到底返回哪个,见FAQ

所以在spiders目录下新建一个spider,dmoz_spider.py:

class DmozSpider(BaseSpider):
   name = "dmoz.org"
   start_urls = [
       "http://www.dmoz.org/Computers/Programming/Languages/Python/Books/",
       "http://www.dmoz.org/Computers/Programming/Languages/Python/Resources/"
   ]

   def parse(self, response):
       filename = response.url.split("/")[-2]
       open(filename, 'wb').write(response.body)

下一步,提取数据到Items里面,这里主要用到XPath提取网页数据:

scrapy有提供两个XPath选择器,HtmlXPathSelector和XmlXPathSelector,一个用于HTML,一个用于XML,XPath选择器有三个方法

  • select(xpath): 返回一个相对于当前选中节点的选择器列表(一个XPath可能选到多个节点)
  • extract(): 返回选择器(列表)对应的节点的字符串(列表)
  • re(regex): 返回正则表达式匹配的字符串(分组匹配)列表

一种很好的方法是在Shell里面对XPath进行测试:

scrapy shell http://www.dmoz.org/Computers/Programming/Languages/Python/Books/

现在修改parse()方法看看如何提取数据到items里面去:

def parse(self, response):
      hxs = HtmlXPathSelector(response)
      sites = hxs.select('//ul/li')
      items = []
      for site in sites:
          item = DmozItem()
          item['title'] = site.select('a/text()').extract()
          item['link'] = site.select('a/@href').extract()
          item['desc'] = site.select('text()').extract()
          items.append(item)
      return items

最后,保存抓取的数据:

scrapy提供了几个选项,可以将数据保存为json,csv或者xml文件,下面开始放出定义的dmoz_spider(注意他的name是dmoz.org),并将抓取的数据保存为json,在dmoz目录下执行命令

scrapy crawl dmoz.org --set FEED_URI=items.json --set FEED_FORMAT=json

如果需要对items数据进一步处理,比如直接保存到数据库,就要用到pipelines

FAQ That Not Included In Manual

不断的抓取下一个链接如何实现,items如何保存?

这里需要解释一下parse()方法,parse可以返回Request列表,或者items列表,如果返回的是Request,则这个Request会放到下一次需要抓取的队列,如果返回items,则对应的items才能传到pipelines处理(或者直接保存,如果使用默认FEED exporter)。那么如果由parse()方法返回下一个链接,那么items怎么返回保存? Request对象接受一个参数callback指定这个Request返回的网页内容的解析函数(实际上start_urls对应的callback默认是parse方法),所以可以指定parse返回Request,然后指定另一个parse_item方法返回items:

def parse(self, response):
    # doSomething
    return [Request(url, callback=self.parse_item)]
def parse_item(self, response):
    # item['key'] = value
    return [item]

关于解析函数的返回值,除了返回列表,其实还可以使用生成器,是等价的:

def parse(self, response):
    # doSomething
    yield Request(url, callback=self.parse_item)
def parse_item(self, response):
    yield item

如何在解析函数之间传递值?

一种常见的情况:在parse中给item某些字段提取了值,但是另外一些值需要在parse_item中提取,这时候需要将parse中的item传到parse_item方法中处理,显然无法直接给parse_item设置而外参数。 Request对象接受一个meta参数,一个字典对象,同时Response对象有一个meta属性可以取到相应request传过来的meta。所以解决上述问题可以这样做:

def parse(self, response):
    # item = ItemClass()
    yield Request(url, meta={'item': item}, callback=self.parse_item)
def parse(self, response):
    item = response.meta['item']
    item['field'] = value
    yield item

pipelines.py如何使用?

具体参考:http://doc.scrapy.org/topics/item-pipeline.html,只需要在settings.py中启用定义的pipelines组件即可,可能困惑的地方在于如果指定了默认的feed exporter,piplelines会对item处理的流程会有什么影响,答案是pipelines会取代默认的feed exporter,项目中所有spider返回的item(比如parse_item)最后都会传入pipelines中定义的proccess_item()方法进一步处理。

Other Tricks

如何处理extract()返回为空列表的情况?

因为extract()方法返回的是字符串列表,如果选择器没有获取到某个节点的内容,则是一个空列表,所以经常会遇到这种处理:

item['field'] = ex_data[0].strip() if len(ex_data) > 0 else ''

一种更好的处理方式:

item['field'] = ''.join(ex_data).strip()

如何给XPath选取内容设置默认值?

XPath选取节点内的文本时,如果节点内容为空,XPath不会返回一个空字符串,而是什么都不返回,对应到列表就是对应的列表项少一项,有时候需要这样的空字符串当默认值。XPath中有一个concat函数可以实现这种效果:

text = hxs.select(‘concat(//span/text(), “”)’).extract()

对于空span会返回一个空字符串

scrapy.log是很好用的调试工具

需要先在settings.py中指定LOG_LEVEL,默认为‘DEBUG’,所以抓取的时候每个item获取的内容都会输出到屏幕,如果抓取的内容太多,有时候会把一些异常信息淹没。所以有时候需要设置高一点的级别,比如‘WARNING’,这样在spider中可以在需要的地方使用log.msg('info', log.WARNING)输出一些有用的信息。

另一种方便的调试方法,在spider中调用交互shell环境

在需要中断调试的地方插入:

from scrapy.shell import inspect_response
inspect_response(response)

这时候会打断抓取,进入一个shell,response为当前抓取的url内容。

[翻译] Experiences from a Decade of TinyOS Development

转载自http://forestgump.me/2012/12/experiences-from-a-decade-of-tinyos-development/ 仅供个人学习用...

Introducing to The Study of Embeded Development from Ten Years Experiences

一、嵌入式系统的概念            着重理解“嵌入”的概念    主要从三个方面上来理解。       1、从硬件上,将基于CPU的处围器件,整合到CPU芯片内部,比如早期基于...
  • msephd
  • msephd
  • 2012年04月25日 15:17
  • 655

What are some good class projects for machine learning using MapReduce?

What are some good class projects for machine learning using MapReduce? We are looking fo...

MyEclipse编辑js的时候出现some characters cannot be mapped using "ISO-8859-1" charater encoding

IDE: Myeclipse Problem: somecharacters cannot be mapped using "ISO-8859-1" charater encoding I...

dplyr do: Some Tips for Using and Programming

This post was originally posted on Quantide blog. Read the full article here. If you want to comp...

some software of my for java delepement

  • 2011年12月22日 17:14
  • 51.6MB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Some Experiences Of Using Scrapy
举报原因:
原因补充:

(最多只允许输入30个字)