介绍

Scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架。 其可以应用在数据挖掘,信息处理或存储历史数据等一系列的程序中。理解scrapy可以参考django,django框架是用帮助我们快速开发web程序的,而scrapy框架就是用来帮助我们快速抓取网页信息的。

安装

#Windows平台1、pip3 install wheel #  pip默认只是去网络去找包,要想pip支持本地wheel文件安装,需要安装wheel包。安装后,便支持通过wheel文件安装软件,wheel文件官网:https://www.lfd.uci.edu/~gohlke/pythonlibs3、pip3 install lxml4、pip3 install pyopenssl5、下载并安装pywin32:https://sourceforge.net/projects/pywin32/files/pywin32/6、下载twisted的wheel文件:http://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted7、执行pip3 install 下载目录\Twisted-17.9.0-cp36-cp36m-win_amd64.whl8、pip3 install scrapy#Linux平台1、pip3 install scrapy

整体架构

在Scrapy的数据流是由执行引擎控制,具体流程如下:

  1. spiders产生request请求,将请求交给引擎
  2. 引擎把请求交给调度器,调度器具有url去重功能(因为request对象里有url),调度器会对需要执行的请求按照优先级排列放到一个地方
  3. 调取器把请求给引擎,引擎把调度好的请求发送给download,通过中间件发送(这个中间件至少有 两个方法,一个请求的,一个返回的)
  4. 一旦完成下载就返回一个response,通过下载器中间件,返回给引擎,引擎把response 对象传给下载器中间件,最后到达引擎
  5. 引擎从下载器中收到response对象,经过爬虫中间件传给了spiders(spiders里面做两件事,1、产生request请求,2、为request请求绑定一个回调函数),spiders只负责解析爬取的任务。不做存储(可以做,但是不建议做,一来是为了分工明确,二来是为了解决重复打开文件的尴尬)
  6. 解析完成之后返回一个解析之后的结果items对象及(跟进的)新的Request给引擎
  7. 引擎将(Spider返回的)爬取到的Item给Item Pipeline,存入数据库,持久化。如果yield的是一个request对象,就传给调度器再次去下载
  8. 重复上述过程

Scrapy主要包括了以下组件:

  • 引擎(Scrapy)
    用来处理整个系统的数据流处理, 触发事务(框架核心)
  • 调度器(Scheduler)
    用来接受引擎发过来的请求, 压入队列中, 并在引擎再次请求的时候返回. 可以想像成一个URL(抓取网页的网址或者说是链接)的优先队列, 由它来决定下一个要抓取的网址是什么, 同时去除重复的网址
  • 下载器(Downloader)
    用于下载网页内容, 并将网页内容返回给蜘蛛(Scrapy下载器是建立在twisted这个高效的异步模型上的)
  • 爬虫(Spiders)
    爬虫是主要干活的, 用于从特定的网页中提取自己需要的信息, 即所谓的实体(Item)。用户也可以从中提取出链接,让Scrapy继续抓取下一个页面
  • 项目管道(Pipeline)
    负责处理爬虫从网页中抽取的实体,主要的功能是持久化实体、验证实体的有效性、清除不需要的信息。当页面被爬虫解析后,将被发送到项目管道,并经过几个特定的次序处理数据。
  • 下载器中间件(Downloader Middlewares)
    位于Scrapy引擎和下载器之间的框架,主要是处理Scrapy引擎与下载器之间的请求及响应。
  • 爬虫中间件(Spider Middlewares)
    介于Scrapy引擎和爬虫之间的框架,主要工作是处理蜘蛛的响应输入和请求输出。
  • 调度中间件(Scheduler Middewares)
    介于Scrapy引擎和调度之间的中间件,从Scrapy引擎发送到调度的请求和响应。

创建项目

scrapy创建项目也是和django创建项目类似

1. scrapy startproject 项目名称- 在当前目录中创建中创建一个项目文件(类似于Django)2. scrapy genspider [-t template] <name> <domain>- 创建爬虫应用,需要cd到项目目录如:scrapy gensipider -t basic oldboy oldboy.comscrapy gensipider -t xmlfeed autohome autohome.com.cnPS:查看所有命令:scrapy gensipider -l查看模板命令:scrapy gensipider -d 模板名称3. scrapy list- 展示爬虫应用列表4. scrapy crawl 爬虫应用名称  - 运行单独爬虫应用,加上--nolog参数就不会打印提示信息

目录结构

 myproject/scrapy.cfg    # 项目部署的配置文件myproject/__init__.pyitems.py          # 用于结构化数据,类似于django中的modelpipelines.py    # 数据处理,一般做数据持久化middlewares.py   # 中间件settings.py    # 爬虫程序使用的配置文件spiders/__init__.pyjd.py       # 文件名一般和爬虫名一样,但是不一样也没关系,因为scrapy crawl jd,使用的是爬虫的name属性

如果在windows中国之行爬虫出现编码问题,在爬虫程序的最上面加上如下代码

import sys,os
sys.stdout=io.TextIOWrapper(sys.stdout.buffer,encoding='gb18030')

起步

# -*- coding: utf-8 -*-
import scrapy
from scrapy.http import Requestclass ChoutiSpider(scrapy.Spider):# 爬虫名称,不能更改name = "chouti"# 爬去过程可能遇到一些a标签,这个选项用来控制爬虫只爬取chouti.com这个网站的连接,不往外爬allowed_domains = ["chouti.com"]# 初始urlstart_urls = ['http://chouti.com/']def start_requests(self):# 爬虫刚开启会执行这个,这个函数要么是一个生成器,要么返回一个可迭代对象,因为源码是把生成器或者可迭代对象通过# iter() 方法转化为迭代器,然后next取值# for url in self.start_urls:#     # 默认callback调用的是parse#     yield Request(url)url_list = []for url in self.start_urls:url_list.append(Request(url))return url_listdef parse(self, response):# response 是爬取得到的对象HtmlResponse,里面不仅封装了响应头,也封装了响应体response.bodyitems = response.xpath('//*[@id="content-list"]/div[@class="item"]')# 每次f = open('chouti.txt', 'a+')for i in items:"""extract 得到列表, extract_first 得到单个值,extract 或 extract_first 得到的里面的内容都是字符串而不是可以使用xpath方法的selector对象"""link = i.xpath('.//a/@href').extract_first()f.write(link + '\n')f.close()page_links = response.xpath('//*[@id="dig_lcpage"]//a/@href').extract()for i in page_links:# 发送下一个请求yield Request(url='https://dig.chouti.com' + i, callback=self.parse)

选择器

在scrapy中可以使用beautifulsoup,但是如果你在scrapy里面使用beautifulsoup就有点非主流了,因为scrapy可以使用xpath语法,关键是在浏览器有一个copy xpath的功能以及xpath组件(crtl + shift + x)可以快速帮我们寻找的我们想要寻找的内容

#!/usr/bin/env python
# -*- coding:utf-8 -*-from scrapy.http import HtmlResponse, Response
from scrapy.selector import Selector
html = """<!DOCTYPE html>
<html><head lang="en"><meta charset="UTF-8"><title></title></head><body><ul><li class="item-"><a id='i1' href="link.html">first item</a></li><li class="item-0"><a id='i2' href="llink.html">first item</a></li><li class="item-1"><a href="llink2.html">second item<span>vv</span></a></li></ul><div><a href="llink2.html">second item</a></div></body>
</html>
"""
response = HtmlResponse(url='http://xxx.com', body=html, encoding='utf8')
# // 表示子子孙孙, / 表示儿子
hxs = response.xpath('//a')
print(hxs)
hxs = response.xpath('//a[2]')
print(hxs)
hxs = response.xpath('//a[@id]')
print(hxs)
hxs = response.xpath('//a[@id="i1"]')
print(hxs)
# 并且的条件
hxs = response.xpath('//a[@href="link.html"][@id="i1"]')
print(hxs)
# 包含,比较常用
hxs = response.xpath('//a[contains(@href, "link")]')
print(hxs)
# 没有end-with
hxs = response.xpath('//a[starts-with(@href, "link")]')
print(hxs)
# 正则表达式,其中re:test 是固定写法
hxs = response.xpath('//a[re:test(@id, "i\d+")]')
print(hxs)
hxs = response.xpath('//a[re:test(@id, "i\d+")]/text()').extract()
print(hxs)
hxs = response.xpath('//a[re:test(@id, "i\d+")]/@href').extract()
print(hxs)
# 抽取li标签下的所有a的href属性组成一个列表,列表里放着字符串
hxs = response.xpath('/html/body/ul/li/a/@href').extract()
print(hxs)
# 抽取li标签下的第一个a的href属性组成一个列表,列表里放着字符串
hxs = response.xpath('//body/ul/li/a/@href').extract_first()
print(hxs)ul_list = response.xpath('//body/ul/li')
for item in ul_list:# 如果这里用item.xpath('/a/span'),那么寻找范围是response,而不是itemv = item.xpath('./a/span')# 或# v = item.xpath('a/span')# 或# v = item.xpath('*/a/span')print(v)

cookie的处理

cookie的处理有两种方式,第一种是自己在程序中获取cookie并每次显示地带上cookie

from scrapy.http.cookies import CookieJarcookie_jar = CookieJar()cookie_jar.extract_cookies(response, response.request)# 去对象中将cookie解析到字典for k, v in cookie_jar._cookies.items():for i, j in v.items():for m, n in j.items():self.cookie_dict[m] = n.value
发送请求时携带cookies,需要注意的一点是body传入的值是‘’k1=1&k2=2‘’这样的格式
yield Request(url='https://xxx',method='post',body='xxoo',cookies=self.cookie_dict,headers = {'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'},callback = self.check_login)from urllib.parse import urlencodedic = {'k1':1,'k2':2
}
print(urlencode(dic))

第二种方式是在每个请求加上这样一句meta={'cookiejar': True},这样发请求的时候会自动解析cookie并携带cookie

pipeline

我们在parse爬取的内容,可以直接在里面打开文件写入文件并关闭文件。但是这样会存在两个问题:

  1. 程序的耦合性较高,因为爬虫代码和存储数据的代码放到一起,这样一旦程序大了就会很乱,我们希望的是爬虫代码就仅仅是爬虫代码,数据持久化代码就只写数据保存相关的逻辑
  2. 一旦在程序设计到翻页,想要再次发请求并且回调函数还是parse的时候,就会重复打开文件,这肯定会浪费资源
    那么我们能否做到在爬虫启动到结束只打开一次文件呢?答案是肯定的,借助item和pipeline就能完成。

cnblogs.py

from nj.items import NjItemclass CnblogSpider(scrapy.Spider):# 爬虫名称,不能更改name = "cnblog"allowed_domains = ["cnblogs.com"]# 初始urlstart_urls = ['https://www.cnblogs.com/longyunfeigu/']def parse(self, response):links = response.xpath("//a[@class='postTitle2']/@href").extract()for link in links:yield NjItem(href=link)

items.py 相当于django的model

import scrapyclass NjItem(scrapy.Item):# define the fields for your item here like:# name = scrapy.Field()href = scrapy.Field()

pipelines.py

# -*- coding: utf-8 -*-# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: http://doc.scrapy.org/en/latest/topics/item-pipeline.html
from scrapy.exceptions import DropItem"""
源码内容:1. 判断当前FilePipeline类中是否有from_crawler有:obj = FilePipeline.from_crawler(....)否:obj = FilePipeline()2. obj.open_spider()3. obj.process_item()/obj.process_item()/obj.process_item()/obj.process_item()/obj.process_item()4. obj.close_spider()
""""""
这里的两个Pipeline不管parse函数是否yield,都会实例化相应的对象并调用open_spider方法,
然后这两个对象就坐在这抽烟等着了,等待着parse返回item对象,然后一层层调用process_item处理,最终爬虫结束的时候接关闭close_spiderraise 一个DropItem() 对象的结果File.from_crawler
DB.from_crawler
File.open_spider
Db.open_spider
File
Db.close_spider
File.close_spider
"""class FilePipeline(object):def __init__(self, path):# 把这个类的对象后续方法可能会用到的属性定义在__init__里面,这样看代码的人一眼就能看到这个对象具有的属性# 否则调用open方法self才有f属性,别人可能有疑惑,明明__init__没有f,现在怎么就有了呢,还得一个个去方法找哪一个给self绑定f属性,这也是编程规范self.f = Noneself.path = path@classmethoddef from_crawler(cls, crawler):"""初始化时候,用于创建pipeline对象,我们在这里取settings的配置,注意我们写的settings不是爬虫所有的配置类似django的settings也不是项目的完整配置:param crawler::return:"""print('File.from_crawler')path = crawler.settings.get('FILE_PATH')return cls(path)def open_spider(self, spider):"""爬虫开始执行时,调用:param spider::return:"""# if spider.name == 'chouti':print('File.open_spider')self.f = open(self.path, 'a+')def process_item(self, item, spider):# f = open('xx.log','a+')# f.write(item['href']+'\n')# f.close()print('File')self.f.write(item.get('href','') + '\n')# 返回item或者返回None, 写一个pipeline都的process_item都会被调用,调用传入的参数就是在这返回的值# 如果返回None,那么下一个pipeline都的process_item的item参数就是None# 要想pipeline都的process_item不再执行,可以使用raise DropItem() 异常实例return item# raise DropItem()def close_spider(self, spider):"""爬虫关闭时,被调用:param spider::return:"""print('File.close_spider')self.f.close()class DbPipeline(object):def __init__(self,path):self.f = Noneself.path = path@classmethoddef from_crawler(cls, crawler):"""初始化时候,用于创建pipeline对象:param crawler::return:"""print('DB.from_crawler')path = crawler.settings.get('DB_PATH')return cls(path)def open_spider(self,spider):"""爬虫开始执行时,调用:param spider::return:"""print('Db.open_spider')self.f = open(self.path,'a+')def process_item(self, item, spider):# f = open('xx.log','a+')# f.write(item['href']+'\n')# f.close()print('Db',item)# self.f.write(item['href']+'\n')return itemdef close_spider(self,spider):"""爬虫关闭时,被调用:param spider::return:"""print('Db.close_spider')self.f.close()

settings.py

ITEM_PIPELINES = {'nj.pipelines.FilePipeline': 300,'nj.pipelines.DbPipeline': 400,
}

转载于:https://www.cnblogs.com/longyunfeigu/p/9485291.html

Scrapy选择器和持久化相关推荐

  1. Python爬虫 --- 2.2 Scrapy 选择器的介绍

    原文链接:www.fkomm.cn/article/201- 在使用Scrapy框架之前,我们必须先了解它是如何筛选数据的 Scrapy提取数据有自己的一套机制,被称作选择器(selectors),通 ...

  2. 学习爬虫之Scrapy框架学习(3)---豆瓣top250电影完整版信息获取及如何存储到mysql数据库;Scrapy shell和Scrapy选择器;使用到日志的学习!

    **豆瓣项目已完结!项目源码: 链接:https://pan.baidu.com/s/1DOnXwXZKiBcJbzHwDJuw5A 提取码:u8xi ** 1.昨天简单爬取了豆瓣Top250电影的一 ...

  3. 爬虫-scrapy数据的持久化存储

    今日概要 基于终端指令的持久化存储 基于管道的持久化存储 1.基于终端指令的持久化存储 保证爬虫文件的parse方法中有可迭代类型对象(通常为列表or字典)的返回,该返回值可以通过终端指令的形式写入指 ...

  4. Python爬虫扩展库scrapy选择器用法入门(一)

    关于BeutifulSoup4的用法入门请参考Python爬虫扩展库BeautifulSoup4用法精要,scrapy爬虫案例请参考Python使用Scrapy爬虫框架爬取天涯社区小说"大宗 ...

  5. Scrapy框架实现持久化存储

    硬盘存储 (1) 基于终端指令 * 保证parse方法返回一个可迭代类型的对象(存储解析到页面内容) * 使用终端指定完成数据存储到磁盘文件的操作      scrapy crawl 爬虫文件名称 - ...

  6. 【Rollo的Python之路】Scrapy Selector选择器的学习

    选择器(Selectors) 当抓取网页时,你做的最常见的任务是从HTML源码中提取数据.现有的一些库可以达到这个目的: BeautifulSoup 是在程序员间非常流行的网页分析库,它基于HTML代 ...

  7. 爬虫学习笔记(七)——Scrapy框架(二):Scrapy shell、选择器

    一.Scrapy shell scrapy shell的作用是用于调试,在项目目录下输入scrapy shell start_urls (start_urls:目标url)得到下列信息: scrapy ...

  8. Scrapy爬虫入门教程五 Selectors(选择器)

    Scrapy爬虫入门教程一 安装和基本使用 Scrapy爬虫入门教程二 官方提供Demo Scrapy爬虫入门教程三 命令行工具介绍和示例 Scrapy爬虫入门教程四 Spider(爬虫) Scrap ...

  9. Scrapy学习笔记(5)--Selectors 选择器

    Selectors选择器 基本介绍 当你在爬取网页的时候,最常见的任务就是从HTML源代码中提取数据. 有几个库可以实现这个功能: BeautifulSoup BeautifulSoup 在Pytho ...

最新文章

  1. springBoot 打war包 程序包com.sun.istack.internal不存在的问题
  2. miniui页面移动的时候透明_【H5】316 移动端H5跳坑指南
  3. android:layout_width=0.0dip,【教程】状态栏显示网速
  4. C#使用集合组织相关数据
  5. 荣耀6plus+android5.1,荣耀66Plus EMUI3.0开发版5.5.1版本发布说明
  6. 什么软件能解答c语言的题,C语言课本习题及解答.pdf
  7. JavaScript操作文件
  8. atitit.架构设计---方法调用结果使用异常还是返回值
  9. (1) python 将numpy数组导出excel
  10. iOS 推送功能打包后获取不到deviceToken
  11. Windows操作系统架构梳理
  12. 电脑远程开机pcie卡
  13. [置顶] 而立之年——三线城市程序员的年终告白
  14. iOS开发UI篇—iPad和iPhone开发的比较
  15. 第 7 章网络可扩展性
  16. 路由器与交换机的工作原理(转)
  17. 5、创建用户微服模块,使用路由网关(gateway 3.0.3)微服进行访问
  18. 海边的卡夫卡之 - kafka的基本概念以及Api使用
  19. CDA数据分析师考察内容包括哪些
  20. php mysql 变量赋值_mysql存储过程中变量的定义赋值操作

热门文章

  1. OpenSuSE 网络配置
  2. Web Components系列(七) ——自定义组件的生命周期
  3. 【前端 · 面试 】HTTP 总结(一)—— HTTP 概述
  4. javascript在IE和Firefox中兼容性问题
  5. Android Permission访问权限许可
  6. Flex之使用DragManager实现对象拖动
  7. 持久化保存iptables规则
  8. Maven——原理与使用(一)
  9. C# 图片处理之:旋转图片任意角度
  10. echart移上去显示内容_Echarts X轴内容过长自动隐藏,鼠标移动上去显示全部名称方法...