[转]Scrapy入门教程
关键字:scrapy 入门教程 爬虫 Spider
作者:http://www.cnblogs.com/txw1958/
出处:http://www.cnblogs.com/txw1958/archive/2012/07/16/scrapy-tutorial.html
在这篇入门教程中,我们假定你已经安装了Scrapy。如果你还没有安装,那么请参考安装指南。
我们将使用开放目录项目(dmoz)作为抓取的例子。
这篇入门教程将引导你完成如下任务:
- 创建一个新的Scrapy项目
- 定义提取的Item
- 写一个Spider用来爬行站点,并提取Items
- 写一个Item Pipeline用来存储提取出的Items
Scrapy是由Python编写的。如果你是Python新手,你也许希望从了解Python开始,以期最好的使用Scrapy。如果你对其它编程语言熟悉,想快速的学习Python,这里推荐 Dive Into Python。如果你对编程是新手,且想从Python开始学习编程,请看下面的对非程序员的Python资源列表。
新建工程
在抓取之前,你需要新建一个Scrapy工程。进入一个你想用来保存代码的目录,然后执行:
Microsoft Windows XP [Version 5.1.2600] (C) Copyright 1985-2001 Microsoft Corp. T:\>scrapy startproject tutorial T:\>
这个命令会在当前目录下创建一个新目录tutorial,它的结构如下:
T:\tutorial>tree /f Folder PATH listing Volume serial number is 0006EFCF C86A:7C52 T:. │ scrapy.cfg │ └─tutorial │ items.py │ pipelines.py │ settings.py │ __init__.py │ └─spiders __init__.py
这些文件主要是:
- scrapy.cfg: 项目配置文件
- tutorial/: 项目python模块, 呆会代码将从这里导入
- tutorial/items.py: 项目items文件
- tutorial/pipelines.py: 项目管道文件
- tutorial/settings.py: 项目配置文件
- tutorial/spiders: 放置spider的目录
定义Item
Items是将要装载抓取的数据的容器,它工作方式像python里面的字典,但它提供更多的保护,比如对未定义的字段填充以防止拼写错误。
它通过创建一个scrapy.item.Item类来声明,定义它的属性为scrpy.item.Field对象,就像是一个对象关系映射(ORM).
我们通过将需要的item模型化,来控制从dmoz.org获得的站点数据,比如我们要获得站点的名字,url和网站描述,我们定义这三种属性的域。要做到这点,我们编辑在tutorial目录下的items.py文件,我们的Item类将会是这样
from scrapy.item import Item, Field class DmozItem(Item): title = Field() link = Field() desc = Field()
刚开始看起来可能会有些困惑,但是定义这些item能让你用其他Scrapy组件的时候知道你的 items到底是什么。
我们的第一个爬虫(Spider)
Spider是用户编写的类,用于从一个域(或域组)中抓取信息。
他们定义了用于下载的URL的初步列表,如何跟踪链接,以及如何来解析这些网页的内容用于提取items。
要建立一个Spider,你必须为scrapy.spider.BaseSpider创建一个子类,并确定三个主要的、强制的属性:
- name:爬虫的识别名,它必须是唯一的,在不同的爬虫中你必须定义不同的名字.
- start_urls:爬虫开始爬的一个URL列表。爬虫从这里开始抓取数据,所以,第一次下载的数据将会从这些URLS开始。其他子URL将会从这些起始URL中继承性生成。
- parse():爬虫的方法,调用时候传入从每一个URL传回的Response对象作为参数,response将会是parse方法的唯一的一个参数,
这个方法负责解析返回的数据、匹配抓取的数据(解析为item)并跟踪更多的URL。
这是我们的第一只爬虫的代码,将其命名为dmoz_spider.py并保存在tutorial\spiders目录下。
class DmozSpider(BaseSpider):
name = "dmoz"
allowed_domains = ["dmoz.org"]
start_urls = [
"http://www.dmoz.org/Computers/Programming/Languages/Python/Books/",
"http://www.dmoz.org/Computers/Programming/Languages/Python/Resources/"
]
def parse(self, response):
filename = response.url.split("/")[-2]
open(filename, 'wb').write(response.body)
爬爬爬
为了让我们的爬虫工作,我们返回项目主目录执行以下命令
T:\tutorial>scrapy crawl dmoz
crawl dmoz 命令从dmoz.org域启动爬虫。 你将会获得如下类似输出
T:\tutorial>scrapy crawl dmoz 2012-07-13 19:14:45+0800 [scrapy] INFO: Scrapy 0.14.4 started (bot: tutorial) 2012-07-13 19:14:45+0800 [scrapy] DEBUG: Enabled extensions: LogStats, TelnetConsole, CloseSpider, WebService, CoreStats, SpiderState 2012-07-13 19:14:45+0800 [scrapy] DEBUG: Enabled downloader middlewares: HttpAuthMiddleware, DownloadTimeoutMiddleware, UserAgentMiddleware, RetryMiddleware, DefaultHeadersMiddleware, RedirectMiddleware, CookiesMiddleware, HttpCompressionMiddleware, ChunkedTransferMiddleware, DownloaderStats 2012-07-13 19:14:45+0800 [scrapy] DEBUG: Enabled spider middlewares: HttpErrorMiddleware, OffsiteMiddleware, RefererMiddleware, UrlLengthMiddleware, DepthMiddleware 2012-07-13 19:14:45+0800 [scrapy] DEBUG: Enabled item pipelines: 2012-07-13 19:14:45+0800 [dmoz] INFO: Spider opened 2012-07-13 19:14:45+0800 [dmoz] INFO: Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0 items/min) 2012-07-13 19:14:45+0800 [scrapy] DEBUG: Telnet console listening on 0.0.0.0:6023 2012-07-13 19:14:45+0800 [scrapy] DEBUG: Web service listening on 0.0.0.0:6080 2012-07-13 19:14:46+0800 [dmoz] DEBUG: Crawled (200) <GET http://www.dmoz.org/Computers/Programming/Languages/Python/Resources/> (referer: None) 2012-07-13 19:14:46+0800 [dmoz] DEBUG: Crawled (200) <GET http://www.dmoz.org/Computers/Programming/Languages/Python/Books/> (referer: None) 2012-07-13 19:14:46+0800 [dmoz] INFO: Closing spider (finished) 2012-07-13 19:14:46+0800 [dmoz] INFO: Dumping spider stats: {'downloader/request_bytes': 486, 'downloader/request_count': 2, 'downloader/request_method_count/GET': 2, 'downloader/response_bytes': 13063, 'downloader/response_count': 2, 'downloader/response_status_count/200': 2, 'finish_reason': 'finished', 'finish_time': datetime.datetime(2012, 7, 13, 11, 14, 46, 703000), 'scheduler/memory_enqueued': 2, 'start_time': datetime.datetime(2012, 7, 13, 11, 14, 45, 500000)} 2012-07-13 19:14:46+0800 [dmoz] INFO: Spider closed (finished) 2012-07-13 19:14:46+0800 [scrapy] INFO: Dumping global stats: {}
注意包含 [dmoz]的行 ,那对应着我们的爬虫。你可以看到start_urls中定义的每个URL都有日志行。因为这些URL是起始页面,所以他们没有引用(referrers),所以在每行的末尾你会看到 (referer: <None>).
有趣的是,在我们的 parse 方法的作用下,两个文件被创建:分别是 Books 和 Resources,这两个文件中有URL的页面内容。
发生了什么事情?
Scrapy为爬虫的 start_urls属性中的每个URL创建了一个 scrapy.http.Request 对象 ,并将爬虫的parse 方法指定为回调函数。
这些 Request首先被调度,然后被执行,之后通过parse()方法,scrapy.http.Response 对象被返回,结果也被反馈给爬虫。
提取Item
选择器介绍
我们有很多方法从网站中提取数据。Scrapy 使用一种叫做 XPath selectors的机制,它基于 XPath表达式。如果你想了解更多selectors和其他机制你可以查阅资料http://doc.scrapy.org/topics/selectors.html#topics-selectors
这是一些XPath表达式的例子和他们的含义
- /html/head/title: 选择HTML文档<head>元素下面的<title> 标签。
- /html/head/title/text(): 选择前面提到的<title> 元素下面的文本内容
- //td: 选择所有 <td> 元素
- //div[@class="mine"]: 选择所有包含 class="mine" 属性的div 标签元素
这只是几个使用XPath的简单例子,但是实际上XPath非常强大。如果你想了解更多XPATH的内容,我们向你推荐这个XPath教程http://www.w3schools.com/XPath/default.asp
为了方便使用XPaths,Scrapy提供XPathSelector 类, 有两种口味可以选择, HtmlXPathSelector (HTML数据解析) 和XmlXPathSelector (XML数据解析)。 为了使用他们你必须通过一个 Response 对象对他们进行实例化操作。你会发现Selector对象展示了文档的节点结构。因此,第一个实例化的selector必与根节点或者是整个目录有关
。
Selectors 有三种方法
- path():返回selectors列表, 每一个select表示一个xpath参数表达式选择的节点.
- extract():返回一个unicode字符串,该字符串为XPath选择器返回的数据
- re(): 返回unicode字符串列表,字符串作为参数由正则表达式提取出来
尝试在shell中使用Selectors
为了演示Selectors的用法,我们将用到 内建的Scrapy shell,这需要系统已经安装IPython (一个扩展python交互环境) 。
附IPython下载地址:http://pypi.python.org/pypi/ipython#downloads
要开始shell,首先进入项目顶层目录,然后输入
T:\tutorial>scrapy shell http://www.dmoz.org/Computers/Programming/Languages/Python/Books/
输出结果类似这样:
2012-07-16 10:58:13+0800 [scrapy] INFO: Scrapy 0.14.4 started (bot: tutorial) 2012-07-16 10:58:13+0800 [scrapy] DEBUG: Enabled extensions: TelnetConsole, CloseSpider, WebService, CoreStats, SpiderState 2012-07-16 10:58:13+0800 [scrapy] DEBUG: Enabled downloader middlewares: HttpAuthMiddleware, DownloadTimeoutMiddleware, UserAgentMiddleware, RetryMiddleware, DefaultHeadersMiddleware, RedirectMiddleware, CookiesMiddleware, HttpCompressionMiddleware, ChunkedTransferMiddleware, DownloaderStats 2012-07-16 10:58:13+0800 [scrapy] DEBUG: Enabled spider middlewares: HttpErrorMiddleware, OffsiteMiddleware, RefererMiddleware, UrlLengthMiddleware, DepthMiddleware 2012-07-16 10:58:13+0800 [scrapy] DEBUG: Enabled item pipelines: 2012-07-16 10:58:13+0800 [scrapy] DEBUG: Telnet console listening on 0.0.0.0:6023 2012-07-16 10:58:13+0800 [scrapy] DEBUG: Web service listening on 0.0.0.0:6080 2012-07-16 10:58:13+0800 [dmoz] INFO: Spider opened 2012-07-16 10:58:18+0800 [dmoz] DEBUG: Crawled (200) <GET http://www.dmoz.org/Computers/Programming/Languages/Python/Books/> (referer: None) [s] Available Scrapy objects: [s] hxs <HtmlXPathSelector xpath=None data=u'<html><head><meta http-equiv="Content-Ty'> [s] item {} [s] request <GET http://www.dmoz.org/Computers/Programming/Languages/Python/Books/> [s] response <200 http://www.dmoz.org/Computers/Programming/Languages/Python/Books/> [s] settings <CrawlerSettings module=<module 'tutorial.settings' from 'T:\tutorial\tutorial\settings.pyc'>> [s] spider <DmozSpider 'dmoz' at 0x1f68230> [s] Useful shortcuts: [s] shelp() Shell help (print this help) [s] fetch(req_or_url) Fetch request (or URL) and update local objects [s] view(response) View response in a browser WARNING: Readline services not available or not loaded.WARNING: Proper color support under MS Windows requires the pyreadline library. You can find it at: http://ipython.org/pyreadline.html Gary's readline needs the ctypes module, from: http://starship.python.net/crew/theller/ctypes (Note that ctypes is already part of Python versions 2.5 and newer). Defaulting color scheme to 'NoColor'Python 2.7.3 (default, Apr 10 2012, 23:31:26) [MSC v.1500 32 bit (Intel)] Type "copyright", "credits" or "license" for more information. IPython 0.13 -- An enhanced Interactive Python. ? -> Introduction and overview of IPython's features. %quickref -> Quick reference. help -> Python's own help system. object? -> Details about 'object', use 'object??' for extra details. In [1]:
Shell载入后,你将获得回应,这些内容被存储在本地变量 response 中,所以如果你输入response.body 你将会看到response的body部分,或者输入response.headers 来查看它的 header部分。
Shell也实例化了两种selectors,一个是解析HTML的 hxs 变量,一个是解析 XML 的 xxs 变量。我们来看看里面有什么:
In [1]: hxs.path('//title') Out[1]: [<HtmlXPathSelector xpath='//title' data=u'<title>Open Directory - Computers: Progr'>] In [2]: hxs.path('//title').extract() Out[2]: [u'<title>Open Directory - Computers: Programming: Languages: Python: Books</title>'] In [3]: hxs.path('//title/text()') Out[3]: [<HtmlXPathSelector xpath='//title/text()' data=u'Open Directory - Computers: Programming:'>] In [4]: hxs.path('//title/text()').extract() Out[4]: [u'Open Directory - Computers: Programming: Languages: Python: Books'] In [5]: hxs.path('//title/text()').re('(\w+):') Out[5]: [u'Computers', u'Programming', u'Languages', u'Python'] In [6]:
提取数据
现在我们尝试从网页中提取数据。
你可以在控制台输入 response.body, 检查源代码中的 XPaths 是否与预期相同。然而,检查HTML源代码是件很枯燥的事情。为了使事情变得简单,我们使用Firefox的扩展插件Firebug。更多信息请查看Using
Firebug for scraping 和Using
Firefox for scraping.
txw1958注:事实上我用的是Google Chrome的Inspect Element功能,而且可以提取元素的XPath。
检查源代码后,你会发现我们需要的数据在一个 <ul>元素中,而且是第二个<ul>。
我们可以通过如下命令选择每个在网站中的 <li> 元素:
hxs.path('//ul/li')
然后是网站描述:
hxs.path('//ul/li/text()').extract()
网站标题:
hxs.path('//ul/li/a/text()').extract()
网站链接:
hxs.path('//ul/li/a/@href').extract()
如前所述,每个path()调用返回一个selectors列表,所以我们可以结合path()去挖掘更深的节点。我们将会用到这些特性,所以:
sites = hxs.path('//ul/li') for site in sites: title = site.path('a/text()').extract() link = site.path('a/@href').extract() desc = site.path('text()').extract() print title, link, desc
Note
更多关于嵌套选择器的内容,请阅读Nesting
selectors 和 Working
with relative XPaths
将代码添加到爬虫中:
txw1958注:代码有修改,绿色注释掉的代码为原教程的,你懂的
from scrapy.spider import BaseSpider from scrapy.selector import HtmlXPathSelector class DmozSpider(BaseSpider): name = "dmoz" allowed_domains = ["dmoz.org"] start_urls = [ "http://www.dmoz.org/Computers/Programming/Languages/Python/Books/", "http://www.dmoz.org/Computers/Programming/Languages/Python/Resources/" ] def parse(self, response): hxs = HtmlXPathSelector(response) sites = hxs.path('//fieldset/ul/li') #sites = hxs.path('//ul/li') for site in sites: title = site.path('a/text()').extract() link = site.path('a/@href').extract() desc = site.path('text()').extract() #print title, link, desc print title, link
现在我们再次抓取dmoz.org,你将看到站点在输出中被打印 ,运行命令
T:\tutorial>scrapy crawl dmoz
使用条目(Item)
Item 对象是自定义的python字典,使用标准字典类似的语法,你可以获取某个字段(即之前定义的类的属性)的值:
>>> item = DmozItem() >>> item['title'] = 'Example title' >>> item['title'] 'Example title'
Spiders希望将其抓取的数据存放到Item对象中。为了返回我们抓取数据,spider的最终代码应当是这样:
from scrapy.spider import BaseSpider from scrapy.selector import HtmlXPathSelector from tutorial.items import DmozItem class DmozSpider(BaseSpider): name = "dmoz" allowed_domains = ["dmoz.org"] start_urls = [ "http://www.dmoz.org/Computers/Programming/Languages/Python/Books/", "http://www.dmoz.org/Computers/Programming/Languages/Python/Resources/" ] def parse(self, response): hxs = HtmlXPathSelector(response) sites = hxs.path('//fieldset/ul/li') #sites = hxs.path('//ul/li') items = [] for site in sites: item = DmozItem() item['title'] = site.path('a/text()').extract() item['link'] = site.path('a/@href').extract() item['desc'] = site.path('text()').extract() items.append(item) return items
现在我们再次抓取 :
2012-07-16 14:52:36+0800 [dmoz] DEBUG: Scraped from <200 http://www.dmoz.org/Computers/Programming/Languages/Python/Books/> {'desc': [u'\n\t\t\t\n\t', u' \n\t\t\t\n\t\t\t\t\t\n - Free Python books and tutorials.\n \n'], 'link': [u'http://www.techbooksforfree.com/perlpython.shtml'], 'title': [u'Free Python books']} 2012-07-16 14:52:36+0800 [dmoz] DEBUG: Scraped from <200 http://www.dmoz.org/Computers/Programming/Languages/Python/Books/> {'desc': [u'\n\t\t\t\n\t', u' \n\t\t\t\n\t\t\t\t\t\n - Annotated list of free online books on Python scripting language. Topics range from beginner to advanced.\n \n '], 'link': [u'http://www.freetechbooks.com/python-f6.html'], 'title': [u'FreeTechBooks: Python Scripting Language']} 2012-07-16 14:52:36+0800 [dmoz] DEBUG: Crawled (200) <GET http://www.dmoz.org/Computers/Programming/Languages/Python/Resources/> (referer: None) 2012-07-16 14:52:36+0800 [dmoz] DEBUG: Scraped from <200 http://www.dmoz.org/Computers/Programming/Languages/Python/Resources/> {'desc': [u'\n\t\t\t\n\t', u' \n\t\t\t\n\t\t\t\t\t\n - A directory of free Python and Zope hosting providers, with reviews and ratings.\n \n'], 'link': [u'http://www.oinko.net/freepython/'], 'title': [u'Free Python and Zope Hosting Directory']} 2012-07-16 14:52:36+0800 [dmoz] DEBUG: Scraped from <200 http://www.dmoz.org/Computers/Programming/Languages/Python/Resources/> {'desc': [u'\n\t\t\t\n\t', u' \n\t\t\t\n\t\t\t\t\t\n - Features Python books, resources, news and articles.\n \n'], 'link': [u'http://oreilly.com/python/'], 'title': [u"O'Reilly Python Center"]} 2012-07-16 14:52:36+0800 [dmoz] DEBUG: Scraped from <200 http://www.dmoz.org/Computers/Programming/Languages/Python/Resources/> {'desc': [u'\n\t\t\t\n\t', u' \n\t\t\t\n\t\t\t\t\t\n - Resources for reporting bugs, accessing the Python source tree with CVS and taking part in the development of Python.\n\n'], 'link': [u'http://www.python.org/dev/'], 'title': [u"Python Developer's Guide"]}
保存抓取的数据
保存信息的最简单的方法是通过Feed exports,命令如下:
T:\tutorial>scrapy crawl dmoz -o items.json -t json
所有抓取的items将以JSON格式被保存在新生成的items.json 文件中
在像本教程一样的小型项目中,这些已经足够。然而,如果你想用抓取的items做更复杂的事情,你可以写一个 Item Pipeline(条目管道)。因为在项目创建的时候,一个专门用于条目管道的占位符文件已经随着items一起被建立,目录在tutorial/pipelines.py。如果你只需要存取这些抓取后的items的话,就不需要去实现任何的条目管道。
结束语
本教程简要介绍了Scrapy的使用,但是许多其他特性并没有提及。
对于基本概念的了解,请访问Basic concepts
我们推荐你继续学习Scrapy项目的例子dirbot,你将从中受益更深,该项目包含本教程中提到的dmoz爬虫。
Dirbot项目位于https://github.com/scrapy/dirbot
项目包含一个README文件,它详细描述了项目的内容。
如果你熟悉git,你可以checkout它的源代码。或者你可以通过点击Downloads下载tarball或zip格式的文件。
另外这有一个代码片断共享网站,里面共享内容包括爬虫,中间件,扩展应用,脚本等。网站名字叫Scrapy snippets,有好的代码要记得共享哦:-)
本教程的源代码下载:https://files.cnblogs.com/txw1958/scrapy_tutorial.rar
每一个不曾起舞的日子,都是对生命的辜负。
But it is the same with man as with the tree. The more he seeks to rise into the height and light, the more vigorously do his roots struggle earthward, downward, into the dark, the deep - into evil.
其实人跟树是一样的,越是向往高处的阳光,它的根就越要伸向黑暗的地底。----尼采
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话