本页代码可以在这里下载。
如果无法启动Scrapy移步这里

PySpider和Scrapy的区别:

前者提供了WebUI,代码的编写、调试都是在WebUI中继续,而后者的原生不具备这个功能,采用代码和命令行操作,但可以通过对接Portia实现可视化配置。
前者调试非常方便,WebUI操作便捷直观。后者则是使用parse命令进行调试。
前者支持PhantomJS来进行JS渲染,而后者可以对接Scrapy-Splash组件,这个需要格外配置。
前者内置pyquery作为选择器,而后者对接XPath和CSS选择器。
前者可扩展程度不足,可配置化程度不高。后者可以通过对接Middleware、Pipeline、Extension 等组件实现非常强大的功能,且模块之间耦合程度低,可扩展程度极高。
 

Scrapy基本介绍:

Scrapy是一个基于Twisted的异步处理框架,是纯Python实现的爬虫框架,其架构清晰,米块之间的耦合程度极低,可扩展性极强,可以灵活完成各种需求。
它可以分为以下几部分:
Engine:引擎,处理整个系统的数据流处理、出发事物,是整个框架的核心。
Item:项目,它定义了爬取结果的数据结构,爬取的数据会被赋值成该Item对象。
Scheduler:调度器,接受引擎发过来的请求并将其加入队列中,在引擎再次请求的时候将请求提供给引擎。
Downloader:下载器,下载网页内容,并将内容返回给蜘蛛。
Spider:蜘蛛,其内定义了爬取的逻辑和网页的解析规则,他主要负责解析响应并生成提取结果和新的请求。
Item Pipeline:项目管道,负责处理由蜘蛛从网页中抽取的项目,它主要任务是清洗、验证和存储。
Downloader Middlewares:下载器中间件,位于引擎和下载器之间的钩子框架,主要处理引擎和下载器之间的请求和相应。
Spider Middlewares:蜘蛛中间件,位于引擎和蜘蛛之间的钩子架构,主要处理蜘蛛输入的响应和输出的结果及新的请求。
 

创建Scrapy:

我们以爬取http://quotes.toscrape.com/ 为例
在命令行中输入scrapy startproject tutorial
其中scrapy startproject是固定启动命令 tutorial是工程名。
创建完成之后当前目录下会多一个tutorial文件夹。

然后进入tutorial目录下,命令行输入:
scrapy genspider quotes quotes.toscrape.com
genspider命令中第一个参数是文件名,第二个参数是URL
创建Spider的子类,用来抓取网页中的内容。

运行结束之后我们看到spiders文件下多了一个quotes.py
其中代码:

# -*- coding: utf-8 -*-
import scrapy
class QuotesSpider(scrapy.Spider):
    name = 'quotes'
    allowed_domains = ['quotes.toscrape.com']
    start_urls = ['http://quotes.toscrape.com/']
    def parse(self, response):
        pass

这里有三个属性:name、allowed_domains 和start_urls,还有一个方法parse。
name:没一个项目唯一的名字,用来区分不同的Spider
allowed_domains:允许爬取的域名,如果初始或后续的请求链接不是这个域名下的,则请求链接会被过滤掉。
start_urls:它包含了Spider在启动时爬取的url列表,初始请求是由它来定义的。
parse:他是Spider的一个方法。默认情况下,被调用start_urls里面的链接构成的请求完成下载执行后,返回响应就会作为唯一的参数传递给这个函数。该方法负责解析返回的响应、提取数据或进一步生成要处理的请求。
 

创建item:

保存爬去数据的容器,使用方法和字典类似,但是多了保护机制,可以避免拼写错误或者定义字段错误。
items.py

# -*- coding: utf-8 -*-
# Define here the models for your scraped items
#
# See documentation in:
# https://doc.scrapy.org/en/latest/topics/items.html
import scrapy
class TutorialItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    text = scrapy.Field()
    author = scrapy.Field()
    tags = scrapy.Field()

quotes.py 下 parse() 方法
然后我们更改quotes.py,注意这里下一页是相对链接,需要使用reljoin转换成绝对链接。

然后处理信息过滤:

# -*- coding: utf-8 -*-
import scrapy
from tutorial.items import TutorialItem
class QuotesSpider(scrapy.Spider):
    name = 'quotes'
    allowed_domains = ['quotes.toscrape.com']
    start_urls = ['http://quotes.toscrape.com/']
    def parse(self, response):
        quotes = response.css('.quote')
        for quote in quotes:
            item = TutorialItem()
            item['text'] = quote.css('.text::text').extract_first()
            item['author'] = quote.css('.author::text').extract_first()
            item['tags'] = quote.css('.tags .tag::text').extract()
            yield item
        # 获取下一页链接
        next = response.css('.pager .next a::attr("href")').extract_first()
        # 处理绝对链接
        url = response.urljoin(next)
        yield scrapy.Request(url=url, callback=self.parse)

 
然后在命令行输入: scrapy crawl quotes
输出爬取结果:

输出到文件:

命令行输入:
scrapy crawl quotes -o quotes.json
这里是输出一个json文件,同样还可以输出.csv、.xml等许多格式。

输出到数据库:

我们可以使用Item Pipeline把数据保存到数据库。
我们可以使用Item Pipeline来做以下操作:
清理HTML数据。
验证爬取数据,检查爬取文字。
查重并丢弃重复内容。
将爬取结果保存到数据库中。
要实现Item Pipeline,只需要定义一个类并实现process_item()方法即可。
修改项目中的pipelines.py文件:

# -*- coding: utf-8 -*-
# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: https://doc.scrapy.org/en/latest/topics/item-pipeline.html
from scrapy.exceptions import DropItem
import pymongo
class TutorialPipeline(object):
    def __init__(self):
        self.limit = 50
    def process_item(self, item, spider):
        if item['text']:
            if len(item['text']) > self.limit:
                # rstrip 删除结尾空格
                item['text'] = item['text'][0:self.limit].rstrip() + '...'
            return item
        else:
            return DropItem('Missing Text')
class MongoPipeline(object):
    def __init__(self, mongo_uri, mongo_db):
        self.mongo_uri = mongo_uri
        self.mongo_db = mongo_db
    @classmethod
    def from_crawler(cls, crawler):
        return cls(
            mongo_uri=crawler.settings.get('MONGO_URI'),
            mongo_db=crawler.settings.get('MONGO_DB')
        )
    def open_spider(self, spider):
        self.client = pymongo.MongoClient(self.mongo_uri)
        self.db = self.client[self.mongo_db]
    def process_item(self, item, spider):
        name = item.__class__,__name__
        self.db[name].insert(dict(item))
        return item
    def close_spider(self,spider):
        self.client.close()

这里我们在构造方法中定义了限制长度50,实现了process_item(),其参数是item和spider,首先该方法判断item的text属性是否存在,如果不存在抛出异常,如果存在,在判断长度是否大于50,如果大于,那就阶段然后拼接省略号,再将item返回。
然后定义了一个类MongoPipeline来保存进数据库:
from_crawler();一个类方法,用@classmethod标识,是一种依赖注入的方式,他的参数就是crawler,通过crawler我们可以拿到全局配置的每个配置信息。在全局配置settings.py中,我们可以定义MONGO_URI 和 MONGO_DB 来指定MongoDB 连接需要的地址和数据库名。即这个方法就是用来获取settings.py中的配置的。
open_spider();当Spider开启时,这个方法被调用,主要进行一些初始化操作。
close_spider();当Spider关闭时,这个方法被调用,主要进行关闭数据库操作。
process_item();执行数据插入操作。
然后在settings.py中添加配置信息:

ITEM_PIPELINES = {
    'tutorial.pipelines.TutorialPipeline': 300,
    'tutorial.pipelines.MongoPipeline': 400
}
MONGO_URI = 'localhost'
MONGO_DB = 'Test'

最后重新运行爬虫,数据库输出如下:

 

Selector 的用法:

selector是Scrapy提供的自己的数据提取方法,它是基于lxml来构建的,支持XPath选择器、CSS选择器以及正则表达式,功能全面,解析速度和准确度非常高。
我们可以直接利用Selector 这个类来构建一个选择器对象,然后调用xpath()、css()等来提取数据。

Spider 的用法:

在Scrapy爬虫项目中,最核心的类就是Spider类了,它定义了如何爬取某个网站的流程和解析方式。
创建爬虫:
在已经创建好项目之后,输入
scrapy genspider name  url 即可创建一个爬虫,文件会存入spiders中

1.name
爬虫名字,必须唯一。
2.allowed_domains
允许爬取的域名,是可选配置
比如这里

如果URL跳出该网站则不被爬取。
3.start_urls
其实URL列表,即从当前列表开始爬取。
4.custom_setting
是一个字典, 是专属于本Spider类的配置,此设置会覆盖项目全局的设置。

我们可以在项目文件中看到settings文件,这个文件中存放了许多默认的值,比如默认请求头等,如果把默认请求头注视掉将无法访问网站,但是我们可以在方法中使用custom_setting,来覆盖或者代替setting,使爬虫可以访问目标网站。

# -*- coding: utf-8 -*-
import scrapy
class ZhihuSpider(scrapy.Spider):
    name = 'zhihu'
    allowed_domains = ['www.zhihu.com']
    start_urls = ['http://www.zhihu.com/']
    custom_settings = {
        'DEFAULT_REQUEST_HEADERS': {
            'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:61.0) Gecko/20100101 Firefox/61.0',
            'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
        }
    }
    def parse(self, response):
        pass

 
5.crawler
它由from_crawler方法设置,代表的是本Spider类对应的Crawler对象,利用它我们可以获取项目的一些配置信息,如piplines中:

6.start_requests
此方法用于声称初始请求,他必须返回一个可迭代对象,我们可以使用此方法更改访问方式。
例如我们如果不加这个方法访问post的时候,则会返回异常状态码,但是加了该方法并加了一个解析函数,我们可以看见正确的访问了页面,并正确执行了解析函数。


7.make_resquests_from_url
更改回调函数(默认parse)

# -*- coding: utf-8 -*-
import scrapy
class BaiduSpider(scrapy.Spider):
    name = 'baidu'
    allowed_domains = ['www.baidu.com']
    start_urls = ['http://www.baidu.com/']
    def make_requests_from_url(self, url):
        return scrapy.Request(url=url, callback=self.parse_index)
    def parse_index(self, response):
        print("Baidu", response.status)
    def parse(self, response):
        pass

Item pipeline 的用法:

项目管道,数据清洗、检查爬取字段,查重并存入数据库。
我们可以自定义item pipeline,只需要实现指定的方法,其中必须要实现的一个方法是process_item(item, spider)
其中
item 是Item对象,即被处理的对象,由parse()生成。
spider是Spider对象,即生成该item的Spider。
还有一些其他的方法:
open_spider(spider):Spider开启的时候被调用。
close_spider(spider):Spider关闭的时候被调用。
from_crawler(cls,crawler):是一个类方法,用@classmethod进行标识,是一种依赖注入的方式。一般来获取一些配置信息,设置等。
我们可以在构造函数中设置一个集合的set()来进行数据去重,其中set()返回的就是数据的集合
self.ids_seen = set()
我们还可以在setting中设置优先级(数字(0~1000)越小,优先级越高)来使用item pipeline

ITEM_PIPELINES = {
    'tutorial.pipelines.TutorialPipeline': 300,
    'tutorial.pipelines.MongoPipeline': 400
}

 
 
 
 
 
 
 
.


0 条评论

发表回复

Avatar placeholder

您的电子邮箱地址不会被公开。 必填项已用 * 标注