scrapy 学习

命令行

在想要创建项目的目录执行命令:scrapy startproject projectname
创建一个爬虫:scrapy genspider mydomain mydomain.com
执行爬虫:scrapy crawl dmoz
shell:scrapy shell "http://XXXXXX"

脚本中运行scrapy

from twisted.internet import reactor
from scrapy.crawler import Crawler
from scrapy import log, signals
from testspiders.spiders.followall import FollowAllSpider
from scrapy.utils.project import get_project_settings

spider = FollowAllSpider(domain='scrapinghub.com')
settings = get_project_settings()
crawler = Crawler(settings)
crawler.signals.connect(reactor.stop, signal=signals.spider_closed)
crawler.configure()
crawler.crawl(spider)
crawler.start()
log.start()
reactor.run() # the script will block here until the spider_closed signal was sent

selector

Selector有四个基本的方法(点击相应的方法可以看到详细的API文档):

  • xpath(): 传入xpath表达式,返回该表达式所对应的所有节点的selector list列表 。
  • css(): 传入CSS表达式,返回该表达式所对应的所有节点的selector list列表.
  • extract(): 序列化该节点为unicode字符串并返回list。
  • re(): 根据传入的正则表达式对数据进行提取,返回unicode字符串list列表。

XPATH

辅助工具:firedebug 复制xpath、xpath checker 插件

CrawlSpider

CrawSpider与Spider区别在于,可以自动对response的页面中符合rules规则的链接进行自动爬取,若一个链接匹配多条规则,默认按第一条规则进行处理,rules为若干个Rule对象的集合,Rule对象包括如下参数:

  • link_extractor 是一个 Link Extractor 对象。 其定义了如何从爬取到的页面提取链接,scrapy将自动根据这些链接创建Request对象,并进行爬取
  • callback 是一个callable或string(该spider中同名的函数将会被调用),其作用是做为根据该规则生成的Request对象的回调函数
  • follow 是一个布尔(boolean)值,指定了是否需要对调用根据该规则生成的Request对象返回的Response进行跟进(不是是否对当前链接进行爬取),是否跟进是指是否将response与rules进行匹配。 如果 callback 为None, follow 默认设置为 True ,否则默认为 False 。对初始url产生的Request,默认进行follow。
  • process_links 是一个callable或string(该spider中同名的函数将会被调用)。 从link_extractor中获取到链接列表时将会调用该函数。该方法主要用来过滤,使用方法如下:
    def process_links(self,links):
        mylinks = []
        for link in links:
            if(link.url=="xxxxxx"):
                mylinks.append(link)
        return mylinks
  • process_request 是一个callable或string(该spider中同名的函数将会被调用)。 该规则提取到每个request时都会调用该函数。该函数必须返回一个request或者None。 (用来过滤request)

CrawlSpider爬取知乎示例:

http://www.jianshu.com/p/b7f41df6202d

# !/usr/bin/env python
#  -*- coding:utf-8 -*-
from scrapy.contrib.spiders import CrawlSpider, Rule
from scrapy.selector import Selector
from scrapy.contrib.linkextractors.sgml import SgmlLinkExtractor
from scrapy.http import Request, FormRequest
from zhihu.items import ZhihuItem



class ZhihuSipder(CrawlSpider) :
    name = "zhihu"
    allowed_domains = ["www.zhihu.com"]
    start_urls = [
        "http://www.zhihu.com"
    ]
    rules = (
        Rule(SgmlLinkExtractor(allow = ('/question/\d+#.*?', )), callback = 'parse_page', follow = True),
        Rule(SgmlLinkExtractor(allow = ('/question/\d+', )), callback = 'parse_page', follow = True),
    )
    headers = {
    "Accept": "*/*",
    "Accept-Encoding": "gzip,deflate",
    "Accept-Language": "en-US,en;q=0.8,zh-TW;q=0.6,zh;q=0.4",
    "Connection": "keep-alive",
    "Content-Type":" application/x-www-form-urlencoded; charset=UTF-8",
    "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.111 Safari/537.36",
    "Referer": "http://www.zhihu.com/"
    }

    #重写了爬虫类的方法, 实现了自定义请求, 运行成功后会调用callback回调函数
    def start_requests(self):
        return [Request("https://www.zhihu.com/login", meta = {'cookiejar' : 1}, callback = self.post_login)]

    #FormRequeset出问题了
    def post_login(self, response):
        print 'Preparing login'
        #下面这句话用于抓取请求网页后返回网页中的_xsrf字段的文字, 用于成功提交表单
        xsrf = Selector(response).xpath('//input[@name="_xsrf"]/@value').extract()[0]
        print xsrf
        #FormRequeset.from_response是Scrapy提供的一个函数, 用于post表单
        #登陆成功后, 会调用after_login回调函数
        return [FormRequest.from_response(response,   #"http://www.zhihu.com/login",
                            meta = {'cookiejar' : response.meta['cookiejar']},
                            headers = self.headers,  #注意此处的headers
                            formdata = {
                            '_xsrf': xsrf,
                            'email': '1095511864@qq.com',
                            'password': '123456'
                            },
                            callback = self.after_login,
                            dont_filter = True
                            )]

    def after_login(self, response) :
        for url in self.start_urls :
            yield self.make_requests_from_url(url)

    def parse_page(self, response):
        problem = Selector(response)
        item = ZhihuItem()
        item['url'] = response.url
        item['name'] = problem.xpath('//span[@class="name"]/text()').extract()
        print item['name']
        item['title'] = problem.xpath('//h2[@class="zm-item-title zm-editable-content"]/text()').extract()
        item['description'] = problem.xpath('//div[@class="zm-editable-content"]/text()').extract()
        item['answer']= problem.xpath('//div[@class=" zm-editable-content clearfix"]/text()').extract()
        return item

Link Extractor

每个LinkExtractor有唯一的公共方法是 extract_links ,它接收一个 Response 对象,并返回一个 scrapy.link.Link 对象。Link Extractors,要实例化一次并且 extract_links 方法会根据不同的response调用多次提取链接。

问题

scrapy的去重机制和深度

如何保存scrapy爬取过的url

def parse(self, response):
        item = DmozItem(link=response.url)
        yield item

CrawlSpider递归爬取:
设置follow为true,或者在parse_item方法中调用parse
Rule(LinkExtractor(allow=('blog.agppp.cn',)), callback='parse_item',follow=True),

def parse_item(self, response):
    item = DmozItem(link=response.url)
    yield item
    for i in self.parse(response):
        yield i

scrapy 设置代理
CrawlSpider详解
request API
response API
XPATH入门教程
scrapy入门教程
scrapy入门教程2