Scrapy

2019-01-05  本文已影响0人  岸与海

scrapy 框架

Scrapy架构图

scrapy.PNG

Scrapy的使用

  1. 创建项目

scrapy startproject 项目名

  1. 创建爬虫文件

scrapy genspider 爬虫名 域名

Scrapy Item pipeline(管道文件)使用

当Item在Spider中被收集之后,它将会被传递到Item Pipeline,这些Item Pipeline组件按定义的顺序处理Item。

每个Item Pipeline都是实现了简单方法的Python类,比如决定此Item是丢弃而存储。以下是item pipeline的一些典型应用:

验证爬取的数据(检查item包含某些字段,比如说name字段)
查重(并丢弃)
将爬取结果保存到文件或者数据库中

下载项目图片

使用图片管道 当使用 ImagesPipeline :

在一个爬虫里,你抓取一个项目,把其中图片的URL放入 image_urls 组内。
项目从爬虫内返回,进入项目管道。
当项目进入 ImagesPipeline,image_urls 组内的URLs将被Scrapy的调度器和下载器(这意味着调度器和下载器的中间件可以复用)安排下载,当优先级更高,会在其他页面被抓取前处理。项目会在这个特定的管道阶段保持“locker”的状态,直到完成图片的下载(或者由于某些原因未完成下载)。
当图片下载完,另一个组(images)将被更新到结构中。这个组将包含一个字典列表,其中包括下载图片的信息,比如下载路径、源抓取地址(从 image_urls 组获得)和图片的校验码。 images 列表中的图片顺序将和源 image_urls 组保持一致。如果某个图片下载失败,将会记录下错误信息,图片也不会出现在 images 组中。

爬虫数据持久化保存

step1: items.py文件:自定义字段,确定要爬取的目标网站数据
step2:spiders/douban.py 文件: 爬虫文件,在这里编写爬虫代码,解析数据,获取新的url
step3:数据持久化

方式一:将数据存入mongodb
settings.py文件: 设置文件,在这里设置User-Agent,激活管道文件
ITEM_PIPELINES = {
    'XXXXXXXXXXX': 300,
}

MONGODB 主机名
MONGODB_HOST = '127.0.0.1'
MONGODB 端口号
MONGODB_PORT= 27017
数据库名称
MONGODB_DBNAME = "XXX"
存储数据的表名称
MONGODB_SHEETNAME= "xxxx"

pipelines.py管道:这里进行数据的清洗和持久化
import pymongo
from scrapy.conf import settings

class DoubanPipeline(object):

    # 将数据存储在mongodb中
    def __init__(self,host,port,dbname,sheetname):
        # 创建MONGODB数据库链接
        client = pymongo.MongoClient(host=host, port=port)
        # 指定数据库
        mydb = client[dbname]
        # 存放数据的集合名称
        self.mysheet = mydb[sheetname]

    @classmethod
    def from_crawler(cls, crawler):
        host = crawler.settings["MONGODB_HOST"]
        port = crawler.settings["MONGODB_PORT"]
        dbname = crawler.settings["MONGODB_DBNAME"]
        sheetname = crawler.settings["MONGODB_SHEETNAME"]
    
        return cls(host,port,dbname,sheetname)

    def process_item(self,item,spider):
        data = dict(item)
        # mongodb数据插入语句,使用save保存数据的效率会很慢,因为它需要循环便利,操作费时
        self.mysheet.insert(data)
        return item
方式二:将数据存入mysql数据库
settings.py文件: 设置文件,在这里设置User-Agent,激活管道文件

ITEM_PIPELINES = {
    'xxxxxxxxxxxxxxxxx': 300,
}

#关于数据库的相关配置
MYSQL_HOST = '127.0.0.1'
MYSQL_PORT = 3306
MYSQL_USER = ''
MYSQL_PWD = ''
MYSQL_DB = ''

pipelines.py管道文件
import pymysql
class DoubanPipeline(object):

#     将数据存储值mysql数据库
#     _mysql_exceptions.OperationalError: (1366, 是因为数据库中的字符集与charset="utf8"不符合

    def __init__(self,host,port,user,pwd,db,charset):
        self.client = pymysql.Connect(host,user,pwd,db,port,charset='utf8')
        self.cursor = self.client.cursor()
    
    @classmethod
    def from_crawler(cls,crawler):
        host = crawler.settings['MYSQL_HOST']
        port = crawler.settings['MYSQL_PORT']
        user = crawler.settings['MYSQL_USER']
        pwd = crawler.settings['MYSQL_PWD']
        db = crawler.settings['MYSQL_DB']

        return cls(host,port,user,pwd,db,charset)

    def process_item(self,item,spider):
        insert_sql = """
               insert into doubanmovie(title, playable, content, star, commentnum, inq)
               VALUE (%s, %s, %s, %s, %s, %s)
        """
        try:
            self.cursor.execute(insert_sql, (item['title'],  item['content'], item['score'], item['info']))
            self.client.commit()
        except Exception as err:
            print(err)
            self.client.rollback()
        return item

将sql语句和要插入的数据在item中定义一个方法返回,通过item调用,然后返回

class XxxxItem(scrapy.Item):

    #名称
    title = scrapy.Field()

    def insert_data_to_db(self,dataDict):
        sql = """
        INSERT INTO caipu (%s)
        VALUES (%s)
        """ % (','.join(dataDict.keys()),','.join(['%s']*len(dataDict)))

        data = list(dataDict.values())

        return sql,data
mysql数据异步插入
#twisted是一个异步的网络框架,这里可以帮助我们实现异步将数据插入数据库

#adbapi里面的子线程会去执行数据库的阻塞操作,当一个线程执行完毕之后,同时,原始线程能继续进行正常的工作,服务其他请求。
import pymysql
from twisted.enterprise import adbapi

#异步插入数据库
class DoubanPipeline(object):

    def __init__(self,dbpool):
        self.dbpool = dbpool

    #使用这个函数来应用settings配置文件。
    @classmethod
    def from_crawler(cls, crawler):
        parmas = {
        'host':crawler.settings['MYSQL_HOST'],
        'user':crawler.settings['MYSQL_USER'],
        'passwd':crawler.settings['MYSQL_PASSWD'],
        'db':crawler.settings['MYSQL_DB'],
        'port':3306,
        'charset':'utf8',
        }

        # **表示字典,*tuple元组,
        # 使用ConnectionPool,起始最后返回的是一个ThreadPool
        dbpool = adbapi.ConnectionPool(
            'pymysql',
            **parmas
        )
        return cls(dbpool)

    def process_item(self, item, spider):
        #这里去调用任务分配的方法
        query = self.dbpool.runInteraction(
            self.insert_data_todb,
            item,
            spider
        )
        #数据插入失败的回调
        query.addErrback(
            self.handle_error,
            item
        )

        #执行数据插入的函数
        def insert_data_todb(self,cursor,item,spider):
            insert_str,parmas = item.insertdata()
            cursor.execute(insert_str,parmas)
            print('插入成功')

    def handle_error(self,failure,item):
        print(failure)
        print('插入错误')
        #在这里执行你想要的操作

    def close_spider(self, spider):
        self.pool.close()

Scrapy Shell 的使用

Scrapy终端是一个交互终端,我们可以在未启动spider的情况下尝试及调试代码,也可以用来测试XPath或CSS表达式,查看他们的工作方式,方便我们爬取的网页中提取的数据。

启动Scrapy Shell

scrapy shell " "
scrapy shell -s USER_AGENT=" "

尝试使用Selector

返回 xpath选择器对象列表

response.xpath('')

使用 extract()方法返回 Unicode字符串列表(打印列表第一个元素,终端编码格式显示)

response.xpath(' ').extract()[0]

返回 xpath选择器对象列表

response.xpath('//title/text()')[0].extract()

Scrapy Spider文件介绍

scrapy.Spider是最基本的类,所有编写的爬虫必须继承这个类

主要用到的函数及调用顺序为:
init() : 初始化爬虫名字和start_urls列表

start_requests() 调用make_requests_from url():生成Requests对象交给Scrapy下载并返回response

parse():

解析response,并返回Item或Requests(需指定回调函数)。
Item传给Item pipline持久化 , 而Requests交由Scrapy下载,并由指定的回调函数处理(默认parse()),一直进行循环,直到处理完所有的数据为止。

Scrapy CrawlSpiders介绍和使用

CrawlSpider它是Spider的派生类,Spider类的设计原则是只爬取start_url列表中的网页,而CrawlSpider类定义了一些规则Rule来提供跟进链接的方便的机制,从爬取的网页结果中获取链接并继续爬取的工作

#######rules
CrawlSpider使用rules属性来决定爬虫的爬取规则,并将匹配后的url请求提交给引擎,完成后续的爬取工作。

在rules中包含一个或多个Rule对象,每个Rule对爬取网站的动作定义了某种特定操作,比如提取当前相应内容里的特定链接,是否对提取的链接跟进爬取,对提交的请求设置回调函数等。

LinkExtractors (目的提取链接)
主要参数:

allow:满足括号中“正则表达式”的URL会被提取,如果为空,则全部匹配。
deny:满足括号中“正则表达式”的URL一定不提取(优先级高于allow)。
allow_domains:会提取的链接的domains。
deny_domains:一定不会被提取链接的domains。
restrict_xpaths:使用xpath表达式,和allow共同作用过滤链接。

Scrapy Request和Response相关参数介绍

Request先关参数介绍

url: 就是需要请求,并进行下一步处理的url

callback: 指定该请求返回的Response,由那个函数来处理。

method: 请求一般不需要指定,默认GET方法,可设置为"GET", "POST", "PUT"等,且保证字符串大写

headers: 请求头

cookies: cookies,模拟用户登录需要指定用户的cookies,字典dict型

meta: 比较常用,在不同的请求之间传递数据使用的。字典dict型

encoding: 编码类型,使用默认的 'utf-8' 就行。

dont_filter: 表明该请求不由调度器过滤。这是当你想使用多次执行相同的请求,忽略重复的过滤器。默认为False。

errback: 指定错误处理函数

Response相关参数介绍

status: 响应码
body: 响应体
url:响应url
self.request (request对象)
self.headers (响应头)

Scrapy DOWNLOADER_MIDDLEWARE 的使用

通常防止爬虫被反主要有以下几个策略

*禁用Cookies(前提是爬取的网站不需要cookies参数)(也就是不启用cookies middleware,不向Server发送cookies,有些网站通过cookie的使用发现爬虫行为)

使用cookies池,自定义中间件

除非特殊需要,否则禁用cookies,防止某些网站根据Cookie来封锁爬虫。

COOKIES_ENABLED = False
设置延迟下载(降低访问网站的频率)(设置为2秒或更高)
DOWNLOAD_DELAY = 2
使用IP代理地址池:VPN和代理IP,现在大部分网站都是根据IP来反爬的。

上一篇 下一篇

猜你喜欢

热点阅读