Python 爬虫框架Scrapy的安装与基本使用(入门)

什么是爬虫

网络爬虫(又称为网页蜘蛛,网络机器人,在FOAF社区中间,更经常的称为网页追逐者),是一种按照一定的规则,自动地抓取万维网信息的程序或者脚本。另外一些不常使用的名字还有蚂蚁、自动索引、模拟程序或者蠕虫。

简单来说,就是通过程序从web网页上获取自己想要的数据,即自动抓取数据。

爬虫的本质

模拟浏览器发送请求从而获取我们想要的数据。

浏览器打开网页的过程:当你在浏览器中输入地址后,通过DNS服务器将域名解析为ip地址找到服务器主机,向服务器发送一个请求,服务器接收请求处理后发送给响应给用户,浏览器接受到结果,包括html,js,css等文件内容,然后浏览器进行相应的处理,最终在页面上呈现出格式化的数据。

用户看到的浏览器的结果一般就是由HTML代码构成的,我们爬虫就是为了获取这些内容,通过分析和过滤html代码,可以从中获取我们想要的资源。

爬虫的基本流程

  • 发起请求:使用HTTP协议向目标主机发起请求,可以包含额外的header等信息,等待服务器响应。
  • 获取响应:如果服务器能正常响应,会得到一个Response,Response的内容便是所要获取的页面内容,类型可能是HTML,Json字符串,二进制数据等类型。
  • 解析内容:得到的内容可能是HTML,可以用正则表达式,页面解析库进行解析,可能是Json,可以直接转换为Json对象解析,可能是二进制数据,可以做保存或者进一步的处理。
  • 保存数据:保存形式多样,可以存为文本,也可以保存到数据库,或者保存特定格式的文件。

能爬取什么样的数据

  • 网页文本:如HTML文档,Json格式化文本等。
  • 图片:获取到的是二进制文件,保存为图片格式。
  • 视频:同样是二进制文件。
  • 其他:只要请求到的,都可以获取。

如何解析数据

  • 直接处理
  • Json解析
  • 正则表达式处理
  • BeautifulSoup解析处理
  • PyQuery解析处理
  • XPath解析处理

关于抓取的页面数据和浏览器里看到的不一样的问题

出现这种情况是因为,很多网站中的数据都是通过js,ajax动态加载的,所以直接通过请求获取的页面和浏览器显示的不同。

如何解决js渲染的问题?

  • 分析ajax
  • Selenium/webdriver
  • Splash
  • PyV8,Ghost.py

爬虫框架Scrapy的安装与基本使用

Scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架。 可以应用在包括数据挖掘,信息处理或存储历史数据等一系列的程序中。

其最初是为了 页面抓取 (更确切来说, 网络抓取 )所设计的, 也可以应用在获取API所返回的数据(例如 Amazon Associates Web Services ) 或者通用的网络爬虫。

Scrapy 使用了Twisted(其主要对手是Tornado)异步网络框架来处理网络通讯,可以加快我们的下载速度,不用自己去实现异步框架,并且包含了各种中间件接口,可以灵活的完成各种需求。

可以参考:
https://github.com/scrapy/scrapy
https://docs.scrapy.org/en/latest/index.html
中文可以参考:
https://github.com/marchtea/scrapy_doc_chs

安装Scrapy框架
pip3 install scrapy

如果你使用anaconda,使用conda install安装:

conda install scrapy	

会问你是不是需要安装依赖的包,输入yes。

本文安装的是Scrapy 1.6.0 版本的。
创建一个scrapy项目
scrapy startproject extraction	

结果显示为:

(ContentExtractionForWebPages) :scrapy startproject extraction
New Scrapy project 'extraction', using template directory '/usr/local/anaconda3/envs/ContentExtractionForWebPages/lib/python3.8/site-packages/scrapy/templates/project', created in:
    /Users/lurongming/mygithub/ContentExtractionForWebPages/extraction

You can start your first spider with:
    cd extraction
    scrapy genspider example example.com

可以使用tree命令查看目录下都创建了哪些文件(如果需要使用tree命令,Mac 可以使用brew install tree来安装):

(ContentExtractionForWebPages) :tree
.
└── extraction
    ├── extraction
    │   ├── __init__.py
    │   ├── __pycache__
    │   ├── items.py
    │   ├── middlewares.py
    │   ├── pipelines.py
    │   ├── settings.py
    │   └── spiders
    │       ├── __init__.py
    │       └── __pycache__
    └── scrapy.cfg

5 directories, 7 files

这些文件分别如下:

  • extraction/ : 该项目的python模块,之后您将在此加入代码。
  • extraction/items.py : 项目中的item文件。相当于一个容器,和字典较像。
  • extraction/middlewares.py :项目中的middlewares.py文件。定义Downloader Middlewares(下载器中间件)和Spider Middlewares(蜘蛛中间件)的实现。
  • extraction/pipelines.py : 项目中的pipelines文件。定义Item Pipeline的实现,实现数据的清洗,储存,验证。
  • extraction/settings.py : 项目的设置文件。
  • extraction/spiders/ : 放置spider代码的目录。
  • scrapy.cfg :配置文件。
创建一个spider

这个类是用来爬取数据的,需要继承 scrapy.Spider 类。需要定义以下三种属性:

  • name: 用于区别Spider。该名字必须是唯一的,不可以为不同的Spider设定相同的名字。
  • start_urls: 包含了Spider在启动时进行爬取的url列表。第一个被获取到的页面将是其中之一,后续的URL则从初始的URL获取到的数据中提取。
  • parse() 是spider的一个方法。 被调用时,每个初始URL完成下载后生成的 Response 对象将会作为唯一的参数传递给该函数。 该方法负责解析返回的数据(response data),提取数据(生成item)以及生成需要进一步处理的URL的 Request 对象。

在extraction/spiders/目录下创建一个文件,spider_demo.py:

import scrapy

class SpiderDemo(scrapy.spiders.Spider):
	name = "SpiderDemo"
	allowed_domains = ["acm.hnucm.edu.cn"]
	start_urls = [
		"http://acm.hnucm.edu.cn/JudgeOnline/problemset.php"
	]

	def parse(self, response):
        filename = "problem"
        with open(filename, 'wb') as f:
            f.write(response.body)

编辑extraction/items.py文件:

(ContentExtractionForWebPages) :vim items.py
(ContentExtractionForWebPages) :cat 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 ExtractionItem(scrapy.Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    # pass
    title = scrapy.Field()
    link = scrapy.Field()
    desc = scrapy.Field()
爬取

运行命令:

scrapy crawl SpiderDemo

如果出现”KeyError: ‘Spider not found:“错误,可能是名字写错了,本文在继承scrapy.spiders.Spider的SpiderDemo类中定义的是name属性是”SpiderDemo“:

class SpiderDemo(scrapy.spiders.Spider):
	name = "SpiderDemo"

结果如下:

(ContentExtractionForWebPages) :scrapy crawl SpiderDemo
2020-02-29 20:54:07 [scrapy.utils.log] INFO: Scrapy 1.6.0 started (bot: extraction)
2020-02-29 20:54:07 [scrapy.utils.log] INFO: Versions: lxml 4.5.0.0, libxml2 2.9.9, cssselect 1.1.0, parsel 1.5.2, w3lib 1.21.0, Twisted 19.10.0, Python 3.8.1 (default, Jan  8 2020, 16:15:59) - [Clang 4.0.1 (tags/RELEASE_401/final)], pyOpenSSL 19.1.0 (OpenSSL 1.1.1d  10 Sep 2019), cryptography 2.8, Platform macOS-10.15.3-x86_64-i386-64bit
2020-02-29 20:54:07 [scrapy.crawler] INFO: Overridden settings: {'BOT_NAME': 'extraction', 'NEWSPIDER_MODULE': 'extraction.spiders', 'ROBOTSTXT_OBEY': True, 'SPIDER_MODULES': ['extraction.spiders']}
2020-02-29 20:54:07 [scrapy.extensions.telnet] INFO: Telnet Password: 41856775cd51cd13
2020-02-29 20:54:07 [scrapy.middleware] INFO: Enabled extensions:
['scrapy.extensions.corestats.CoreStats',
 'scrapy.extensions.telnet.TelnetConsole',
 'scrapy.extensions.memusage.MemoryUsage',
 'scrapy.extensions.logstats.LogStats']
2020-02-29 20:54:07 [scrapy.middleware] INFO: Enabled downloader middlewares:
['scrapy.downloadermiddlewares.robotstxt.RobotsTxtMiddleware',
 'scrapy.downloadermiddlewares.httpauth.HttpAuthMiddleware',
 'scrapy.downloadermiddlewares.downloadtimeout.DownloadTimeoutMiddleware',
 'scrapy.downloadermiddlewares.defaultheaders.DefaultHeadersMiddleware',
 'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware',
 'scrapy.downloadermiddlewares.retry.RetryMiddleware',
 'scrapy.downloadermiddlewares.redirect.MetaRefreshMiddleware',
 'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware',
 'scrapy.downloadermiddlewares.redirect.RedirectMiddleware',
 'scrapy.downloadermiddlewares.cookies.CookiesMiddleware',
 'scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware',
 'scrapy.downloadermiddlewares.stats.DownloaderStats']
2020-02-29 20:54:07 [scrapy.middleware] INFO: Enabled spider middlewares:
['scrapy.spidermiddlewares.httperror.HttpErrorMiddleware',
 'scrapy.spidermiddlewares.offsite.OffsiteMiddleware',
 'scrapy.spidermiddlewares.referer.RefererMiddleware',
 'scrapy.spidermiddlewares.urllength.UrlLengthMiddleware',
 'scrapy.spidermiddlewares.depth.DepthMiddleware']
2020-02-29 20:54:07 [scrapy.middleware] INFO: Enabled item pipelines:
[]
2020-02-29 20:54:07 [scrapy.core.engine] INFO: Spider opened
2020-02-29 20:54:07 [scrapy.extensions.logstats] INFO: Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0 items/min)
2020-02-29 20:54:07 [scrapy.extensions.telnet] INFO: Telnet console listening on 127.0.0.1:6023
2020-02-29 20:54:07 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://acm.hnucm.edu.cn/robots.txt> (referer: None)
2020-02-29 20:54:07 [scrapy.downloadermiddlewares.robotstxt] DEBUG: Forbidden by robots.txt: <GET http://acm.hnucm.edu.cn/JudgeOnline/problemset.php>
2020-02-29 20:54:07 [scrapy.core.engine] INFO: Closing spider (finished)
2020-02-29 20:54:07 [scrapy.statscollectors] INFO: Dumping Scrapy stats:
{'downloader/exception_count': 1,
 'downloader/exception_type_count/scrapy.exceptions.IgnoreRequest': 1,
 'downloader/request_bytes': 225,
 'downloader/request_count': 1,
 'downloader/request_method_count/GET': 1,
 'downloader/response_bytes': 274,
 'downloader/response_count': 1,
 'downloader/response_status_count/200': 1,
 'finish_reason': 'finished',
 'finish_time': datetime.datetime(2020, 2, 29, 12, 54, 7, 623854),
 'log_count/DEBUG': 2,
 'log_count/INFO': 9,
 'memusage/max': 47665152,
 'memusage/startup': 47661056,
 'response_received_count': 1,
 'robotstxt/forbidden': 1,
 'robotstxt/request_count': 1,
 'robotstxt/response_count': 1,
 'robotstxt/response_status_count/200': 1,
 'scheduler/dequeued': 1,
 'scheduler/dequeued/memory': 1,
 'scheduler/enqueued': 1,
 'scheduler/enqueued/memory': 1,
 'start_time': datetime.datetime(2020, 2, 29, 12, 54, 7, 259481)}
2020-02-29 20:54:07 [scrapy.core.engine] INFO: Spider closed (finished)

可以看到出了问题:

2020-02-29 20:54:07 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://acm.hnucm.edu.cn/robots.txt> (referer: None)
2020-02-29 20:54:07 [scrapy.downloadermiddlewares.robotstxt] DEBUG: Forbidden by robots.txt: <GET http://acm.hnucm.edu.cn/JudgeOnline/problemset.php>
2020-02-29 20:54:07 [scrapy.core.engine] INFO: Closing spider (finished)

看到是Forbidden by robots.txt。

关于robots.txt这个文件,百度如下:

robots协议也叫robots.txt(统一小写)是一种存放于网站根目录下的ASCII编码的文本文件,它通常告诉网络搜索引擎的漫游器(又称网络蜘蛛),此网站中的哪些内容是不应被搜索引擎的漫游器获取的,哪些是可以被漫游器获取的。因为一些系统中的URL是大小写敏感的,所以robots.txt的文件名应统一为小写。robots.txt应放置于网站的根目录下。如果想单独定义搜索引擎的漫游器访问子目录时的行为,那么可以将自定的设置合并到根目录下的robots.txt,或者使用robots元数据(Metadata,又称元数据)。
robots协议并不是一个规范,而只是约定俗成的,所以并不能保证网站的隐私。

就是说,robots.txt 这个文件中规定了本站点允许的爬虫机器爬取的范围(比如你不想让别人爬取你的页面,就可以通过robot来限制,然而可能并没什么用。。),因为默认scrapy遵守robot协议,所以会先请求这个文件查看权限,所以scrapy就停止了之后的请求和页面解析。

关于这个协议看到了下面一则旧闻,额。。。

百度起诉360
百度诉奇虎360违反“Robots协议”抓取、复制其网站内容侵权一案,2013年10月16日上午在北京市第一中级人民法院开庭审理。百度方面认为,360搜索在未获得百度公司允许的情况下,违反业内公认的Robots协议,抓取百度旗下百度知道、百度百科、百度贴吧等网站的内容,已经构成了不正当竞争,并向奇虎索赔1亿元。

我们在setting改变ROBOTSTXT_OBEY为False,让scrapy不要遵守robot协议,之后就能正常爬取了。

修改extraction/settings.py文件:

 21 # Obey robots.txt rules
 22 # ROBOTSTXT_OBEY = True
 23 ROBOTSTXT_OBEY = False

将ROBOTSTXT_OBEY 设置为 False,然后再运行看看:

(ContentExtractionForWebPages) :scrapy crawl SpiderDemo
2020-02-29 21:05:07 [scrapy.utils.log] INFO: Scrapy 1.6.0 started (bot: extraction)
2020-02-29 21:05:07 [scrapy.utils.log] INFO: Versions: lxml 4.5.0.0, libxml2 2.9.9, cssselect 1.1.0, parsel 1.5.2, w3lib 1.21.0, Twisted 19.10.0, Python 3.8.1 (default, Jan  8 2020, 16:15:59) - [Clang 4.0.1 (tags/RELEASE_401/final)], pyOpenSSL 19.1.0 (OpenSSL 1.1.1d  10 Sep 2019), cryptography 2.8, Platform macOS-10.15.3-x86_64-i386-64bit
2020-02-29 21:05:07 [scrapy.crawler] INFO: Overridden settings: {'BOT_NAME': 'extraction', 'NEWSPIDER_MODULE': 'extraction.spiders', 'SPIDER_MODULES': ['extraction.spiders']}
2020-02-29 21:05:07 [scrapy.extensions.telnet] INFO: Telnet Password: bfabdd27e26f8717
2020-02-29 21:05:07 [scrapy.middleware] INFO: Enabled extensions:
['scrapy.extensions.corestats.CoreStats',
 'scrapy.extensions.telnet.TelnetConsole',
 'scrapy.extensions.memusage.MemoryUsage',
 'scrapy.extensions.logstats.LogStats']
2020-02-29 21:05:07 [scrapy.middleware] INFO: Enabled downloader middlewares:
['scrapy.downloadermiddlewares.httpauth.HttpAuthMiddleware',
 'scrapy.downloadermiddlewares.downloadtimeout.DownloadTimeoutMiddleware',
 'scrapy.downloadermiddlewares.defaultheaders.DefaultHeadersMiddleware',
 'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware',
 'scrapy.downloadermiddlewares.retry.RetryMiddleware',
 'scrapy.downloadermiddlewares.redirect.MetaRefreshMiddleware',
 'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware',
 'scrapy.downloadermiddlewares.redirect.RedirectMiddleware',
 'scrapy.downloadermiddlewares.cookies.CookiesMiddleware',
 'scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware',
 'scrapy.downloadermiddlewares.stats.DownloaderStats']
2020-02-29 21:05:07 [scrapy.middleware] INFO: Enabled spider middlewares:
['scrapy.spidermiddlewares.httperror.HttpErrorMiddleware',
 'scrapy.spidermiddlewares.offsite.OffsiteMiddleware',
 'scrapy.spidermiddlewares.referer.RefererMiddleware',
 'scrapy.spidermiddlewares.urllength.UrlLengthMiddleware',
 'scrapy.spidermiddlewares.depth.DepthMiddleware']
2020-02-29 21:05:07 [scrapy.middleware] INFO: Enabled item pipelines:
[]
2020-02-29 21:05:07 [scrapy.core.engine] INFO: Spider opened
2020-02-29 21:05:07 [scrapy.extensions.logstats] INFO: Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0 items/min)
2020-02-29 21:05:07 [scrapy.extensions.telnet] INFO: Telnet console listening on 127.0.0.1:6023
2020-02-29 21:05:09 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://acm.hnucm.edu.cn/JudgeOnline/problemset.php> (referer: None)
2020-02-29 21:05:09 [scrapy.core.engine] INFO: Closing spider (finished)
2020-02-29 21:05:09 [scrapy.statscollectors] INFO: Dumping Scrapy stats:
{'downloader/request_bytes': 241,
 'downloader/request_count': 1,
 'downloader/request_method_count/GET': 1,
 'downloader/response_bytes': 68611,
 'downloader/response_count': 1,
 'downloader/response_status_count/200': 1,
 'finish_reason': 'finished',
 'finish_time': datetime.datetime(2020, 2, 29, 13, 5, 9, 621906),
 'log_count/DEBUG': 1,
 'log_count/INFO': 9,
 'memusage/max': 47693824,
 'memusage/startup': 47693824,
 'response_received_count': 1,
 'scheduler/dequeued': 1,
 'scheduler/dequeued/memory': 1,
 'scheduler/enqueued': 1,
 'scheduler/enqueued/memory': 1,
 'start_time': datetime.datetime(2020, 2, 29, 13, 5, 7, 222700)}
2020-02-29 21:05:09 [scrapy.core.engine] INFO: Spider closed (finished)
>>>

好像没啥问题了,输出ls看一下结果:

(ContentExtractionForWebPages) :ls
__init__.py	items.py	pipelines.py	settings.py
__pycache__	middlewares.py	problem		spiders

可以看到创建了problem文件,输出problem文件的内容:

。。。
网页源码
。。。

在数据比较多的情况下,直接看网络源码是很费时间的,所以我们需要有效的提取数据,如何提取有效的数据呢?

scrapy提供了帮我们处理数据的方式。可以使用Selectors选择器来选择我们想要的数据。

Selectors选择器

Selectors选择器:

从网页中提取数据有很多方法。Scrapy使用了一种基于 XPath 和 CSS 表达式机制: Scrapy Selectors。

Selector有四个基本的方法:

  • xpath(): 传入xpath表达式,返回该表达式所对应的所有节点的selector list列表 。
  • css(): 传入CSS表达式,返回该表达式所对应的所有节点的selector list列表.
  • extract(): 序列化该节点为unicode字符串并返回list。
  • re(): 根据传入的正则表达式对数据进行提取,返回unicode字符串list列表。
在Shell中尝试Selector选择器
scrapy shell "http://acm.hnucm.edu.cn/JudgeOnline/problemset.php"

可以看到输出如下:

...
2020-02-29 21:40:47 [scrapy.core.engine] INFO: Spider opened
2020-02-29 21:40:47 [scrapy.core.engine] DEBUG: Crawled (200) <GET http://acm.hnucm.edu.cn/JudgeOnline/problemset.php> (referer: None)
[s] Available Scrapy objects:
[s]   scrapy     scrapy module (contains scrapy.Request, scrapy.Selector, etc)
[s]   crawler    <scrapy.crawler.Crawler object at 0x10f915730>
[s]   item       {}
[s]   request    <GET http://acm.hnucm.edu.cn/JudgeOnline/problemset.php>
[s]   response   <200 http://acm.hnucm.edu.cn/JudgeOnline/problemset.php>
[s]   settings   <scrapy.settings.Settings object at 0x10f9154f0>
[s]   spider     <SpiderDemo 'SpiderDemo' at 0x10fc85430>
[s] Useful shortcuts:
[s]   fetch(url[, redirect=True]) Fetch URL and update local objects (by default, redirects are followed)
[s]   fetch(req)                  Fetch a scrapy.Request and update local objects 
[s]   shelp()           Shell help (print this help)
[s]   view(response)    View response in a browser
>>>

当shell载入后会得到一个包含response数据的本地 response 变量。输入 response.body 将输出response的包体, 输出 response.headers 可以看到response的包头。

试一下:

>>> response.headers

获取到了以下信息:

{b’Server’: [b’nginx/1.14.2’], b’Date’: [b’Sat, 29 Feb 2020 19:57:17 GMT’], b’Content-Type’: [b’text/html; charset=UTF-8’], b’Set-Cookie’: [b’PHPSESSID=n1muaj25ap4s2vld3cak6qt0m0; path=/’], b’Expires’: [b’Thu, 19 Nov 1981 08:52:00 GMT’], b’Cache-Control’: [b’no-store, no-cache, must-revalidate’], b’Pragma’: [b’no-cache’], b’X-Frame-Options’: [b’SAMEORIGIN’]}

输入 response.selector 时, 您将获取到一个可以用于查询返回数据的selector(选择器), 以及映射到 response.selector.xpath() 、 response.selector.css() 的 快捷方法(shortcut): response.xpath() 和 response.css() 。

同时,shell根据response提前初始化了变量 sel 。该selector根据response的类型自动选择最合适的分析规则(XML vs HTML)。

试一下:

获取所有的title:

>>> response.xpath('//title')
[<Selector xpath='//title' data='<title>\n\t\tHNUCM-OJ\t</title>'>]

获取所有的题目列表:

通过观察网页结构,我发现因为题目都是有个链接的,指向problem.php并传入id。使用正则表达式获取所有<a>中有href属性,并且href属性包含problem.php?id=的:

>>> response.xpath('//a[contains(@href,"problem.php?id=")]/text()').extract()

于是就获取了以下的题目:

[‘Biggest Number’, ‘Repairing a Road’, ‘射击游戏’, ‘战场的数目’, ‘Infinite Dictionaries’, ‘Tetrahedrons and Spheres’, '一二三 ', ‘报数游戏’, '多连块拼图 ', ‘多连块分解’, ‘盒子游戏’, ‘打怪升级’, ‘最优对称路径’, ‘Pieces and Discs’, ‘Super Poker’, ‘Super Poker II’, ‘RMQ with Shifts’, ‘XP的简单题’, ‘机器人的指令’, ‘Updating a Dictionary’, ‘平方根大搜索’, ‘最短的名字’, ‘Kingdoms’, ‘网格中的三角形’, ‘Tin Cutter II’, ‘Collecting Coins’, ‘病毒’, ‘Cross-Shaped Tests’, ‘安全区域’, ‘近似回文词’, ‘一行盒子’, ‘字符识别?’, ‘Damaging Your Spreadsheet (Spreadsheet Tracking II)’, ‘割耳法’, ‘Funny Car Racing’, ‘好老师’, ‘高桥和低桥’, ‘Interesting Calculator’, ‘和费马开个玩笑’, ‘Killer Puzzle’, ‘最后一滴血’, '点到圆弧的距离 ', '积木玩具 ', '酷酷的单词 ‘, ’ Double Shortest Paths’, ‘超大型 LED 显示屏’, ‘地图的四着色’, 'Giving directions to the tree ', 'Happy Robot ', '残缺的棋盘 ', ‘Just another pachinko-like machine’, 'Kick the ball! ', 'Aerial Tramway ', '大还是小? ', '多边形的公共部分 ', '错误的算法 ', '简单的图论问题? ', ’ 阶乘除法 ', ‘Graph Guessing’, '聊天止于呵呵 ', ’ Internet of Lights and Switches ', '又一道简单题 ', 'Keep Fit! ', ‘Julyed’, ‘Fibonacci’, ‘Proxy’, ‘Swiss-system tournament’, ‘The Binding of Isaac’, ‘Feed the monkey’, ‘Triple Nim’, ‘Memory Leak’, ‘Rock Paper Scissors’, ‘Execution of Paladin’, ‘Reversed Words’, ‘Password’, ‘Return of the Nim’, ‘Quadrat’, ‘fireworks’, ‘HEX’, ‘news reporter’, ‘quadratic equation’, ‘sum of power’, ‘triangle’, ‘Parity check’, ‘company’, ‘CF’, ‘#6002. 「网络流 24 题」最小路径覆盖’, ‘#6003. 「网络流 24 题」魔术球’, ‘#6005. 「网络流 24 题」最长递增子序列’, ‘#6007. 「网络流 24 题」方格取数’, ‘#6008. 「网络流 24 题」餐巾计划’, ‘#6009. 「网络流 24 题」软件补丁’, ‘#6010. 「网络流 24 题」数字梯形’, ‘#6011. 「网络流 24 题」运输问题’, ‘#6012. 「网络流 24 题」分配问题’]

以上是简单的使用。

scrapy还提供了Items Pipeline等机制更好的处理数据。

下次再学。。。

发布了78 篇原创文章 · 获赞 3 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/LU_ZHAO/article/details/104575394