2025-02-07
编程
00
请注意,本文编写于 80 天前,最后修改于 79 天前,其中某些信息可能已经过时。

目录

1.安装并创建scrapy项目
1.安装
2.开始创建一个爬虫项目
3.进入创建的爬虫项目
4.创建爬虫itcast,域名为"itcast.cn"(爬虫名不能和项目名重合)
5.改造起始url
6.引入管道文件(MyspiderItem为爬虫项目名首字母大写+Item)
7.更改配置文件
8.爬虫测试
2.更改配置文件
3.修改起始url并解析数据
4.编写item接收数据
5.设置爬虫中间件和下载中间件
6.pipeline保存数据
7.设置日志的使用
8.CrawlSpider
1. 创建一个CrawlSpider爬虫
2. 导入:
3. 实例
9.Scrapy 命令行工具(Command line tools)
创建项目
控制项目
startproject
genspider
crawl
check
list
fetch
view
shell
parse
settings
runspider
version
deploy
bench

爬虫进阶之scrapy框架的详细使用

默认的Scrapy项目结构

scrapy.cfg myproject/ __init__.py items.py pipelines.py settings.py spiders/ __init__.py spider1.py spider2.py ...

scrapy.cfg 存放的目录被认为是项目的根目录,该文件中包含python模块名的字段定义了项目的设置。例如:

[settings] default = myproject.settings

1.安装并创建scrapy项目

1.安装

pip install scrapy -i https://pypi.mirrors.ustc.edu.cn/simple/

2.开始创建一个爬虫项目

scrapy startproject mySpider

3.进入创建的爬虫项目

cd mySpider

4.创建爬虫itcast,域名为"itcast.cn"(爬虫名不能和项目名重合)

scrapy genspider itcast "itcast.cn"

5.改造起始url

start_urls = ["https://douban.com"]

6.引入管道文件(MyspiderItem为爬虫项目名首字母大写+Item)

from mySpider.mySpider.items import MyspiderItem

7.更改配置文件

# 遵循robots.txt中的爬虫规则,可以选False ROBOTSTXT_OBEY = False #通过LOG_LEVEL来设置日志输出级别,有如下四种日志级别DEBUG,INFO,WARNING,ERROR LOG_LEVEL="WARNING" #通过LOG_FILE来设置日志输出位置 LOG_FILE="./log.log"

8.爬虫测试

scrapy crawl myspider

2.更改配置文件

# 自动生成的配置,无需关注,不用修改 BOT_NAME = "mySpider" SPIDER_MODULES = ["mySpider.spiders"] NEWSPIDER_MODULE = "mySpider.spiders" #通过LOG_LEVEL来设置日志输出级别,有如下四种日志级别DEBUG,INFO,WARNING,ERROR LOG_LEVEL="WARNING" #通过LOG_FILE来设置日志输出位置 LOG_FILE="./log.log" # 配置起始USER_AGENT,但不常用,一般都是在MiddleWare中添加 #USER_AGENT = "mySpider (+http://www.yourdomain.com)" # 遵循robots.txt中的爬虫规则,可以选False ROBOTSTXT_OBEY = True # 对网站并发请求总数,默认16 #CONCURRENT_REQUESTS = 32 # 相同网站两个请求之间的间隔时间,默认是0s。相当于time.sleep() #DOWNLOAD_DELAY = 3 # ---下面两个配置二选一,但其值不能大于CONCURRENT_REQUESTS,默认启用PER_DOMAIN--- # 对网站每个域名的最大并发请求,默认8 #CONCURRENT_REQUESTS_PER_DOMAIN = 16 # 默认0,对网站每个IP的最大并发请求,会覆盖上面PER_DOMAIN配置, # 同时DOWNLOAD_DELAY也成了相同IP两个请求间的间隔了 #CONCURRENT_REQUESTS_PER_IP = 16 # 禁用cookie,默认是True,启用 #COOKIES_ENABLED = False # 禁止控制台使用telnet连接scrapy获取状态,默认是启用。我们使用默认值即可 #TELNETCONSOLE_ENABLED = False # # 请求头设置,这里基本上不用 #DEFAULT_REQUEST_HEADERS = { # "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", # "Accept-Language": "en", #} # 配置启用SPIDER MiddleWares SPIDER_MIDDLEWARES = { "mySpider.middlewares.MyspiderSpiderMiddleware": 543, } # 配置启用Downloader MiddleWares,数据值就代表的是Downloader MiddleWares的执行顺序,值越小越先执行 DOWNLOADER_MIDDLEWARES = { "mySpider.middlewares.MyspiderDownloaderMiddleware": 542, "mySpider.middlewares.SeleniumMiddleware": 543, } # 配置并启用扩展,主要是一些状态监控 #EXTENSIONS = { # "scrapy.extensions.telnet.TelnetConsole": None, #} # 配置启用Pipeline用来持久化,数据值就代表的是pipeline的执行顺序,值越小越先执行 ITEM_PIPELINES = { "mySpider.pipelines.MyspiderPipeline": 300, "mySpider.pipelines.MyspiderPipeline1": 301, } # AutoThrottle是限速节流算法 # 让爬虫程序自适应download_delay和concurrent并发 #AUTOTHROTTLE_ENABLED = True # 爬虫程序启动时,开始对网站发起请求的延迟 #AUTOTHROTTLE_START_DELAY = 5 # 请求到响应的最大允许的延迟时间,必须大于download_delay #AUTOTHROTTLE_MAX_DELAY = 60 # 并行发送到每个远程服务器的平均请求数,小于CONCURRENT_REQUESTS_PER_DOMAIN和CONCURRENT_REQUESTS_PER_IP #AUTOTHROTTLE_TARGET_CONCURRENCY = 1.0 # 为每个响应启用显示限制统计信息 #AUTOTHROTTLE_DEBUG = False # 配置启用HTTP Cache,默认不启用 #HTTPCACHE_ENABLED = True # 缓存的过期时间,0为永不过期 #HTTPCACHE_EXPIRATION_SECS = 0 # 缓存目录名称 #HTTPCACHE_DIR = "httpcache" # 设置不需要缓存的状态码请求 #HTTPCACHE_IGNORE_HTTP_CODES = [] # 此类将缓存保存到本地文件系统,还可以使用其他类保存到数据库 #HTTPCACHE_STORAGE = "scrapy.extensions.httpcache.FilesystemCacheStorage" # Set settings whose default value is deprecated to a future-proof value REQUEST_FINGERPRINTER_IMPLEMENTATION = "2.7" TWISTED_REACTOR = "twisted.internet.asyncioreactor.AsyncioSelectorReactor" FEED_EXPORT_ENCODING = "utf-8"

3.修改起始url并解析数据

import json import scrapy from mySpider.mySpider.items import MyspiderItem#引入管道 class DoubanSpider(scrapy.Spider): name = "douban" allowed_domains = ["douban.com"] #start_requests不能改是方法的重写 def start_requests(self): start_urls = ["https://douban.com"] cookies = { "a":"1", "b":"2" } for url in start_urls: #添加 dont_filter=True 参数,这样 Scrapy 就不会过滤掉重复的请求 yield scrapy.Request(url=url, callback=self.parse,dont_filter=False) def parse(self, response): url2 = response.re('......').extract_first() name = response.xpath('......').extract() year = response.css('......').extract() # 管道名称用文件名加管道 item = MyspiderItem() #meta = {'item': item}传递数据 yield scrapy.Request(url=url2, callback=self.parse2, dont_filter=False,meta = {'item': item}) def parse2(self, response): #加载或解析数据 result = json.load(response.text) for image in result.get('list'): # 管道名称传递用法 item = response.meta['item'] item['id'] = image.get('imageid') item['url'] = image.get('qhimg_url') item['title'] = image.get('group_title') item['thumb'] = image.get('qhimg_thumb_url') yield item

4.编写item接收数据

# Define here the models for your scraped items # # See documentation in: # https://docs.scrapy.org/en/latest/topics/items.html import scrapy class MyspiderItem(scrapy.Item): name = scrapy.Field() title = scrapy.Field() info = scrapy.Field()

5.设置爬虫中间件和下载中间件

置header或cookies或ip代理,以及集成selenium

注意

要在setting中对中间件进行设置

# 使用之前要在setting中打开通道 #爬虫中间件和下载中间件注册在设置哪里,就是那个中间件 # See documentation in: https://docs.scrapy.org/en/latest/topics/spider-middleware.html import base64 import random import time import webbrowser from scrapy import signals # useful for handling different item types with a single interface from itemadapter import is_item, ItemAdapter class MyspiderSpiderMiddleware(object): @classmethod def from_crawler(cls, crawler): s = cls() crawler.signals.connect(s.spider_opened, signal=signals.spider_opened) return s def process_spider_input(self, response, spider): return None def process_spider_output(self, response, result, spider): for i in result: yield i def process_spider_exception(self, response, exception, spider): pass def process_start_requests(self, start_requests, spider): for r in start_requests: yield r def spider_opened(self, spider): spider.logger.info("Spider opened: %s" % spider.name) class MyspiderDownloaderMiddleware(object): @classmethod def from_crawler(cls, crawler): s = cls() crawler.signals.connect(s.spider_opened, signal=signals.spider_opened) return s def process_request(self, request, spider): # ---------------添加user_angent头------------------- user_angent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36" request.headers['User-Agent'] = user_angent # ---------------添加ip代理------------------- proxy_list = [ {"ip_port": "123.107.53.84","user_passwd":"username_abcdef"},#存在密码的代理 {"ip_port": "123.107.53.84"},#不存在密码的代理 ] proxy = random.choice(proxy_list) #如果ip存在密码 if "user_passwd" in proxy: #对密码进行base64编码 b64_up = base64.b64encode(proxy["user_passwd"].encode()) #设置认证 request.headers['Proxy-Autherization'] = 'Basic' + b64_up.decode() #设置代理 request.meta['proxy'] = proxy['ip_port'] else: # 设置代理 request.meta['proxy'] = proxy['ip_port'] def process_response(self, request, response, spider): return response def process_exception(self, request, exception, spider): pass def spider_opened(self, spider): spider.logger.info("Spider opened: %s" % spider.name) class SeleniumMiddleware(object): def process_request(self, request, spider): url = request.url if 'davdata' in url: web = webbrowser.Chrome() web.get(url) time.sleep(3) data = web.page_source web.close() #创建响应对象 res = HtmlResponse(url=url,body=data,encodings='utf-8',request=request)

6.pipeline保存数据

注意

如果想要使用pipeline,首先需要开启pipeline,这个是在settings.py文件中配置的

# 果想要使用pipeline,首先需要开启pipeline,这个是在settings.py文件中配置的 import json import pymysql class MyspiderPipeline: #初始化可用__init__ def open_spider(self, spider): # 在爬虫开启的时候仅执行一次 self.f = open('job2.json', 'w', encoding='utf-8') def process_item(self, item, spider): #json.dumps(dict(item)将类转换为字典,然后转换为json self.f.write(json.dumps(dict(item), ensure_ascii=False)) self.f.write('\n') return item def close_spider(self, spider): # 在爬虫关闭的时候仅执行一次 self.f.close() class MyspiderPipeline2: #初始化 def __init__(self): self.conn = pymysql.connect( host="", port="", user="", password="", database="" ) self.cursor = self.conn.cursor() def process_item(self, item, spider): sql = "insert into book values (null,'%s','%s')"%(item["name"],item["password"]) self.cursor.excute(sql) self.conn.commit() def close_spider(self, spider): # 在爬虫关闭的时候仅执行一次 self.cursor.close() self.conn.close()

7.设置日志的使用

在setting设置log的级别和输出位置

#通过LOG_LEVEL来设置日志输出级别,有如下四种日志级别DEBUG,INFO,WARNING,ERROR LOG_LEVEL="WARNING" #通过LOG_FILE来设置日志输出位置 LOG_FILE="./log.log"

设置日志的输出样式

import logging logging.basicConfig( level=logging.INFO, format='%(asctime)s %(filename)s %(levelname)s %(message)s', datefmt='%a %d %b %Y %H:%M:%S' ) logger = logging.getLogger(__name__) if __name__ == '__main__': logger.info('this is a info log') logger.info('this is a info log1')

8.CrawlSpider

re匹配查找url地址
CrawlSpider 是 Scrapy 提供的一个通用 Spider。 在 Spider 里,我们可以指定一些爬取规则来实现页面的提取,这些爬取规则由一个专门的数据结构 Rule 表示。 Rule 里包含提取和跟进页面的配置, Spider 会根据 Rule来确定当前页面中的哪些链接需要继续爬取、哪些页面的爬取结果需要用哪个方法解析等。

1. 创建一个CrawlSpider爬虫

scrapy genspider -t crawl spider_name domain.com

tip: 要比以往Spider爬虫建立时多了一个 -t crawl

2. 导入:

from scrapy.linkextractors import LinkExtractor from scrapy.spiders import CrawlSpider, Rule

3. 实例

rules:

allow 匹配的地址
callback 回调函数
follow 当前的url会进入并重新提取url
process_request 是一个callable或string(该spider中同名的函数将会被调用)。该规则提取到每个request时都会调用该函数。该函数必须返回一个request或者None。

import re import string import random from scrapy.linkextractors import LinkExtractor from scrapy.spiders import CrawlSpider, Rule from ..items import DoubanbookspiderItem class BookspdSpider(CrawlSpider): name = 'bookspd' allowed_domains = ['douban.com'] start_urls = ['https://book.douban.com/subject/1040771/'] rules = ( Rule(LinkExtractor(allow=r'/subject/\d+/$'), callback='parse_item', follow=True, process_request='get_cookie'), #process_request 是一个callable或string(该spider中同名的函数将会被调用)。该规则提取到每个request时都会调用该函数。该函数必须返回一个request或者None。 ) def get_cookie(self, request): bid = ''.join(random.choice(string.ascii_letters + string.digits) for x in range(11)) request.cookies['bid'] = bid return request def parse_item(self, response): item = DoubanbookspiderItem() item['id'] = re.findall(r'/subject/(\d+)/', response.url)[0] item['cover'] = ''.join(response.xpath('//div[@id="mainpic"]/a[@class="nbg"]/@href').extract()) item['name'] = ''.join(response.xpath('//span[@property="v:itemreviewed"]/text()').extract()) item['Originalname'] = ''.join(response.xpath('//div[@id="info"]').re('原作名:</span>\s(.*)<br>')) item['author'] = ''.join(response.xpath('//div[@id="info"]//span[contains(text(), "作者")]/../a[1]/text()').extract()).replace(' ','').replace('\n','') item['publisher'] = ''.join(response.xpath('//div[@id="info"]').re('出版社:</span>\s(.*)<br>')) item['publishdate'] = ''.join(response.xpath('//div[@id="info"]').re('出版年:</span>\s(.*)<br>')) item['pages'] = ''.join(response.xpath('//div[@id="info"]').re('页数:</span>\s(.*)<br>')) item['price'] = ''.join(response.xpath('//div[@id="info"]').re('定价:</span>\s(.*)<br>')) item['rating_num'] = response.xpath('//strong[@property="v:average"]/text()').extract_first() item['rating_people'] = response.xpath('//span[@property="v:votes"]/text()').extract_first() yield item

9.Scrapy 命令行工具(Command line tools)

使用 scrapy 工具 您可以以无参数的方式启动Scrapy工具。该命令将会给出一些使用帮助以及可用的命令:

Scrapy X.Y - no active project Usage: scrapy <command> [options] [args] Available commands: crawl Run a spider fetch Fetch a URL using the Scrapy downloader [...]

如果您在Scrapy项目中运行,当前激活的项目将会显示在输出的第一行。上面的输出就是响应的例子。如果您在一个项目中运行命令将会得到类似的输出:

Scrapy X.Y - project: myproject Usage: scrapy <command> [options] [args] [...]

创建项目

一般来说,使用 scrapy 工具的第一件事就是创建您的Scrapy项目:

scrapy startproject myproject

该命令将会在 myproject 目录中创建一个Scrapy项目。 接下来,进入到项目目录中:

cd myproject

这时候您就可以使用 scrapy 命令来管理和控制您的项目了。

控制项目

您可以在您的项目中使用 scrapy 工具来对其进行控制和管理。 比如,创建一个新的spider:

scrapy genspider mydomain mydomain.com

有些Scrapy命令(比如 crawl)要求必须在Scrapy项目中运行。 您可以通过下边的 commands reference 来了解哪些命令需要在项目中运行,哪些不用。
另外要注意,有些命令在项目里运行时的效果有些许区别。 以fetch命令为例,如果被爬取的url与某个特定spider相关联, 则该命令将会使用spider的动作(spider-overridden behaviours)。 (比如spider指定的 user_agent)。 该表现是有意而为之的。一般来说, fetch 命令就是用来测试检查spider是如何下载页面。 可用的工具命令(tool commands)
该章节提供了可用的内置命令的列表。每个命令都提供了描述以及一些使用例子。您总是可以通过运行命令来获取关于每个命令的详细内容:

scrapy <command> -h

您也可以查看所有可用的命令:

scrapy -h

Scrapy提供了两种类型的命令。一种必须在Scrapy项目中运行(针对项目(Project-specific)的命令),另外一种则不需要(全局命令)。全局命令在项目中运行时的表现可能会与在非项目中运行有些许差别(因为可能会使用项目的设定)。

全局命令: ● startproject ● settings ● runspider ● shell ● fetch ● view ● version 项目(Project-only)命令: ● crawl ● check ● list ● edit ● parse ● genspider ● deploy ● bench

startproject

● 语法: scrapy startproject <project_name>
● 是否需要项目: no
在 project_name 文件夹下创建一个名为 project_name 的Scrapy项目。
$ scrapy startproject myproject

genspider

● 语法: scrapy genspider [-t template] <name> <domain>
● 是否需要项目: yes
在当前项目中创建spider。
这仅仅是创建spider的一种快捷方法。该方法可以使用提前定义好的模板来生成spider。您也可以自己创建spider的源码文件。

$ scrapy genspider -l Available templates: basic crawl csvfeed xmlfeed $ scrapy genspider -d basic import scrapy class $classname(scrapy.Spider): name = "$name" allowed_domains = ["$domain"] start_urls = ( 'http://www.$domain/', ) def parse(self, response): pass $ scrapy genspider -t basic example example.com Created spider 'example' using template 'basic' in module: mybot.spiders.example

crawl

● 语法: scrapy crawl <spider> ● 是否需要项目: yes 使用spider进行爬取。

$ scrapy crawl myspider [ ... myspider starts crawling ... ]

check

● 语法: scrapy check [-l] <spider> ● 是否需要项目: yes 运行contract检查。

$ scrapy check -l first_spider * parse * parse_item second_spider * parse * parse_item $ scrapy check [FAILED] first_spider:parse_item >>> 'RetailPricex' field is missing [FAILED] first_spider:parse >>> Returned 92 requests, expected 0..4

list

● 语法: scrapy list
● 是否需要项目: yes
列出当前项目中所有可用的spider。每行输出一个spider。

$ scrapy list spider1 spider2 edit

● 语法: scrapy edit <spider>
● 是否需要项目: yes
使用 EDITOR 中设定的编辑器编辑给定的spider
该命令仅仅是提供一个快捷方式。开发者可以自由选择其他工具或者IDE来编写调试spider。

$ scrapy edit spider1

fetch

● 语法: scrapy fetch <url>
● 是否需要项目: no
使用Scrapy下载器(downloader)下载给定的URL,并将获取到的内容送到标准输出。 该命令以spider下载页面的方式获取页面。例如,如果spider有 USER_AGENT 属性修改了 User Agent,该命令将会使用该属性。
因此,您可以使用该命令来查看spider如何获取某个特定页面。
该命令如果非项目中运行则会使用默认Scrapy downloader设定。

$ scrapy fetch --nolog http://www.example.com/some/page.html [ ... html content here ... ] $ scrapy fetch --nolog --headers http://www.example.com/ {'Accept-Ranges': ['bytes'], 'Age': ['1263 '], 'Connection': ['close '], 'Content-Length': ['596'], 'Content-Type': ['text/html; charset=UTF-8'], 'Date': ['Wed, 18 Aug 2010 23:59:46 GMT'], 'Etag': ['"573c1-254-48c9c87349680"'], 'Last-Modified': ['Fri, 30 Jul 2010 15:30:18 GMT'], 'Server': ['Apache/2.2.3 (CentOS)']}

view

● 语法: scrapy view <url>
● 是否需要项目: no
在浏览器中打开给定的URL,并以Scrapy spider获取到的形式展现。 有些时候spider获取到的页面和普通用户看到的并不相同。 因此该命令可以用来检查spider所获取到的页面,并确认这是您所期望的。

$ scrapy view http://www.example.com/some/page.html [ ... browser starts ... ]

shell

● 语法: scrapy shell [url]
● 是否需要项目: no
以给定的URL(如果给出)或者空(没有给出URL)启动Scrapy shell。 查看 Scrapy终端(Scrapy shell) 获取更多信息。

$ scrapy shell http://www.example.com/some/page.html [ ... scrapy shell starts ... ]

parse

● 语法: scrapy parse <url> [options]
● 是否需要项目: yes
获取给定的URL并使用相应的spider分析处理。如果您提供 --callback 选项,则使用spider的该方法处理,否则使用 parse 。
支持的选项:
● --spider=SPIDER: 跳过自动检测spider并强制使用特定的spider
● --a NAME=VALUE: 设置spider的参数(可能被重复)
● --callback or -c: spider中用于解析返回(response)的回调函数
● --pipelines: 在pipeline中处理item
● --rules or -r: 使用 CrawlSpider 规则来发现用来解析返回(response)的回调函数
● --noitems: 不显示爬取到的item
● --nolinks: 不显示提取到的链接
● --nocolour: 避免使用pygments对输出着色
● --depth or -d: 指定跟进链接请求的层次数(默认: 1)
● --verbose or -v: 显示每个请求的详细信息

$ scrapy parse http://www.example.com/ -c parse_item [ ... scrapy log lines crawling example.com spider ... ] >>> STATUS DEPTH LEVEL 1 <<< # Scraped Items ------------------------------------------------------------ [{'name': u'Example item', 'category': u'Furniture', 'length': u'12 cm'}] # Requests ----------------------------------------------------------------- []

settings

● 语法: scrapy settings [options]
● 是否需要项目: no
获取Scrapy的设定
在项目中运行时,该命令将会输出项目的设定值,否则输出Scrapy默认设定。

$ scrapy settings --get BOT_NAME scrapybot $ scrapy settings --get DOWNLOAD_DELAY 0

runspider

● 语法: scrapy runspider <spider_file.py>
● 是否需要项目: no
在未创建项目的情况下,运行一个编写在Python文件中的spider。

$ scrapy runspider myspider.py [ ... spider starts crawling ... ]

version

● 语法: scrapy version [-v]
● 是否需要项目: no
输出Scrapy版本。配合 -v 运行时,该命令同时输出Python, Twisted以及平台的信息,方便bug提交。

deploy

0.11 新版功能. ● 语法: scrapy deploy [ <target:project> | -l <target> | -L ]
● 是否需要项目: yes
将项目部署到Scrapyd服务。查看 部署您的项目 。

bench

0.17 新版功能.
● 语法: scrapy bench
● 是否需要项目: no
运行benchmark测试。 Benchmarking 。
自定义项目命令
您也可以通过 COMMANDS_MODULE 来添加您自己的项目命令。您可以以 scrapy/commands 中Scrapy commands为例来了解如何实现您的命令。
COMMANDS_MODULE
Default: '' (empty string)
用于查找添加自定义Scrapy命令的模块。
例子:

COMMANDS_MODULE = 'mybot.commands'

文章如有错误,还望留言指正

参考资料
特殊原因,不便展示,请见谅