Python爬虫框架Scrapy爬虫文件之spider介绍(四)
laoyan 2017-09-14 14:35:44
分 享


背景简介


python的scrapy中Spider类定义了如何爬取某个(或某些)网站。包括了爬取的动作(例如:是否跟进链接)以及如何从网页的内容中提取结构化数据(爬取item)。 换句话说,Spider就是您定义爬取的动作及分析某个网页(或者是有些网页)的地方。


对spider来说,爬取的循环类似下文:


(1)以初始的URL初始化Request,并设置回调函数。 当该request下载完毕并返回时,将生成response,并作为参数传给该回调函数。


spider中初始的request是通过调用 start_requests() 来获取的。 start_requests() 读取 start_urls 中的URL, 并以 parse 为回调函数生成 Request 。


(2)在回调函数内分析返回的(网页)内容,返回 Item 对象、dict、 Request 或者一个包括三者的可迭代容器。 返回的Request对象之后会经过Scrapy处理,下载相应的内容,并调用设置的callback函数(函数可相同)。


(3)在回调函数内,您可以使用 选择器(Selectors) (您也可以使用BeautifulSoup, lxml 或者您想用的任何解析器) 来分析网页内容,并根据分析的数据生成item。


(4)最后,由spider返回的item将被存到数据库(由某些 Item Pipeline 处理)或使用 Feed exports 存入到文件中。


虽然该循环对任何类型的spider都(多少)适用,但Scrapy仍然为了不同的需求提供了多种默认spider。 之后将讨论这些spider。


spider源码参考


class Spider(object_ref):
    """Base class for scrapy spiders. All spiders must inherit from this
    class.
    """
    name = None
    custom_settings = None
    def __init__(self, name=None, **kwargs):
        if name is not None:
            self.name = name
        elif not getattr(self, 'name', None):
            raise ValueError("%s must have a name" % type(self).__name__)
        self.__dict__.update(kwargs)
        if not hasattr(self, 'start_urls'):
            self.start_urls = []
    @property
    def logger(self):
        logger = logging.getLogger(self.name)
        return logging.LoggerAdapter(logger, {'spider': self})
    def log(self, message, level=logging.DEBUG, **kw):
        """Log the given message at the given log level
        This helper wraps a log call to the logger within the spider, but you
        can use it directly (e.g. Spider.logger.info('msg')) or use any other
        Python logger too.
        """
        self.logger.log(level, message, **kw)
    @classmethod
    def from_crawler(cls, crawler, *args, **kwargs):
        spider = cls(*args, **kwargs)
        spider._set_crawler(crawler)
        return spider
    def set_crawler(self, crawler):
        warnings.warn("set_crawler is deprecated, instantiate and bound the "
                      "spider to this crawler with from_crawler method "
                      "instead.",
                      category=ScrapyDeprecationWarning, stacklevel=2)
        assert not hasattr(self, 'crawler'), "Spider already bounded to a " \
                                             "crawler"
        self._set_crawler(crawler)
    def _set_crawler(self, crawler):
        self.crawler = crawler
        self.settings = crawler.settings
        crawler.signals.connect(self.close, signals.spider_closed)
    def start_requests(self):
        for url in self.start_urls:
            yield self.make_requests_from_url(url)
    def make_requests_from_url(self, url):
        return Request(url, dont_filter=True)
    def parse(self, response):
        raise NotImplementedError
    @classmethod
    def update_settings(cls, settings):
        settings.setdict(cls.custom_settings or {}, priority='spider')
    @classmethod
    def handles_request(cls, request):
        return url_is_from_spider(request.url, cls)
    @staticmethod
    def close(spider, reason):
        closed = getattr(spider, 'closed', None)
        if callable(closed):
            return closed(reason)
    def __str__(self):
        return "<%s %r at 0x%0x>" % (type(self).__name__, self.name, id(self))
    __repr__ = __str__


主要属性和方法


1、name


定义了sipder名字的字符串


例如,如果spider爬取lybbn.cn,该spider通常会被命名为lybbn,此方法为必选方法


2、allowed_domains


包含了spider允许爬取的域名(domain)的列表,此方法为可选方法


3、start_urls


初始url元组/列表,当没有指定特定的url时,spider将从该列表中开始进行爬取


4、parse(self,response)


parse 负责处理response并返回处理的数据以及(/或)跟进的URL。 Spider 对其他的Request的回调函数也有相同的要求。该方法及其他的Request回调函数必须返回一个包含 Request、dict 或 Item 的可迭代的对象。


5、log(self,message[, level, component])


使用 scrapy.log.msg() 方法记录(log)message。 log中自动带上该spider的 name 属性。 更多数据请参见 Logging 。 封装了通过Spiders的 logger 来发送log消息的方法,并且保持了向后兼容性


爬虫spider建立


方法一:你可以直接使用命令的方式建立


genspider命令用于创建爬虫文件,后面需要跟两个参数,一个是爬虫名称,一个是允许爬行的域名



如果爬虫文件中有包含爬虫名称,会提示,已存在该名称的spider文件


scrapy genspider lybbn "lybbn.cn"


Spider 'lybbn' already exists in module:

  lybbnspider.spiders.lybbn_spider


scrapy  lybbn01 "lybbn01.cn"

Spider 'lybbn' already exists in module:

  lybbnspider.spiders.lybbn_spider


命令创建的爬虫文件


# -*- coding: utf-8 -*-
import scrapy
class Lybbn01Spider(scrapy.Spider):
    name = 'lybbn01'
    allowed_domains = ['lybbn.cn']
    start_urls = ['http://www.lybbn.cn/']
    def parse(self, response):
        pass


方法二:你可以自己建立sipder文件不需要命令


spider爬虫实例自动翻页


方法一:拼接URL的方式来实现翻页(该场景弊端在于网站数据有变化或者url地址变化的话,拼接URL就不适用了)


#coding=utf-8
from scrapy.spiders import Spider
from scrapy.selector import Selector
from scrapy.http import Request
from lybbnspider.items import LybbnspiderItem
  
class LybbnSpider(Spider):
    name="lybbn"
    allowed_domains=["lybbn.cn"]
    baseURL="http://www.lybbn.cn/index.php?page="
    offset=1
    start_urls=[baseURL+str(offset)]
    def parse(self,response):
        sel=Selector(response)
        mylis=sel.xpath('//*[@id="excerpt"]/li')
        for myli in mylis:
            item=LybbnspiderItem()
            item['title']=myli.xpath('h2/a/text()').extract()
            item['link']=myli.xpath('h2/a/@href').extract()
            yield item
        if self.offset<17:#判断offset是分页的末尾页的情况下
            self.offset+=1
            url=self.baseURL+str(self.offset)
            yield Request(url,callback=self.parse)



方法二:通过网页中找到下一页的链接的方式实现自动翻页


#coding=utf-8
from scrapy.spiders import Spider
from scrapy.selector import Selector
from scrapy.http import Request
from lybbnspider.items import LybbnspiderItem
  
class LybbnSpider(Spider):
    name="lybbn"
    allowed_domains=["lybbn.cn"]
    start_urls=["http://www.lybbn.cn/index.php?page=1"]
    def parse(self,response):
        sel=Selector(response)
        mylis=sel.xpath('//*[@id="excerpt"]/li')
        for myli in mylis:
            item=LybbnspiderItem()
            item['title']=myli.xpath('h2/a/text()').extract()
            item['link']=myli.xpath('h2/a/@href').extract()
            yield item
        if len(response.css(u'#page :contains("下一页")::attr(href)').extract())!=0:#判断下一页是否灰色不可点
            url=response.css(u'#page :contains("下一页")::attr(href)').extract()[0].encode('utf-8')#由于本网站下一页的xpath不规则,因此使用css提取含有下一页的标签的href值。
            yield Request("http://www.lybbn.cn/index.php"+url,callback=self.parse)


spider爬虫实例跟踪链接获取文章内容


#coding=utf-8
from scrapy.spiders import Spider
from scrapy.selector import Selector
from scrapy.http import Request
from lybbnspider.items import LybbnspiderItem
  
class LybbnSpider(Spider):
    name="lybbn"
    allowed_domains=["lybbn.cn"]
    start_urls=["http://www.lybbn.cn/index.php?page=1"]
    def parse(self,response):
        sel=Selector(response)
        mylis=sel.xpath('//*[@id="excerpt"]/li')
        for myli in mylis:
            content_url=myli.xpath('h2/a/@href').extract()[0]
            yield Request(content_url,callback=self.parse_content)
        if len(response.css(u'#page :contains("下一页")::attr(href)').extract())!=0:#判断下一页是否灰色不可点
            url=response.css(u'#page :contains("下一页")::attr(href)').extract()[0].encode('utf-8')#由于本网站下一页的xpath不规则,因此使用css提取含有下一页的标签的href值。
            yield Request("http://www.lybbn.cn/index.php"+url,callback=self.parse)
    def parse_content(self,response):
        item=LybbnspiderItem()
        item['title']=response.xpath('//*[@id="hg1"]/div[1]/div[1]/text()').extract()[0].strip()
        item['content']=response.xpath('//*[@id="article"]').extract()[0]
        item['link']=response.url
        yield item


传送门


Python爬虫框架Scrapy介绍(一)


http://www.lybbn.cn/data/datas.php?yw=260


Python爬虫框架Scrapy之爬取下一页网页的方法(二)


http://www.lybbn.cn/data/datas.php?yw=261


Python爬虫框架Scrapy之管道文件pipeline介绍(三)


http://www.lybbn.cn/data/datas.php?yw=266


相关连接


官方网站:http://scrapy.org/
开源地址:https://github.com/scrapy/scrapy
中文文档:http://scrapy-chs.readthedocs.io/zh_CN/latest/intro/overview.html



转载请注明来自Lybbn(lybbn.cn)

我要小额支持下

取消

感谢您的支持,我会继续努力的!

扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

取消
吐槽一下

游客

所有吐槽
  • 暂时还没有吐槽,赶紧来吐槽!