尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Scrapy 官方教程实战:从创建项目到递归爬虫、数据导出与 Spider 参数全流程解析

Scrapy 官方教程实战:从创建项目到递归爬虫、数据导出与 Spider 参数全流程解析 Scrapy 官方教程实战从创建项目到递归爬虫、数据导出与 Spider 参数全流程解析【免费下载链接】scrapyScrapy, a fast high-level web crawling scraping framework for Python.项目地址: https://gitcode.com/GitHub_Trending/sc/scrapy本篇指南基于 Scrapy 官方教程文档docs/intro/tutorial.rst以 quotes.toscrape.com 网站为练习对象带你完整走通 Scrapy 爬虫开发的核心闭环创建项目、编写 Spider、用 Scrapy Shell 调试选择器、提取数据、导出 JSON/JSON Lines 文件、递归跟随链接以及通过命令行参数驱动 Spider。学完后你既能独立搭建可运行的 Scrapy 项目也能结合本仓库源码理解start/parse回调机制、-o/-O/-a选项的实现原理以及链接去重等底层行为。教程假设 Scrapy 已安装到你的系统安装方法可参阅 安装指南。教程覆盖的五个任务官方教程将学习路径拆分为五个递进任务本文按此脉络展开创建一个全新的 Scrapy 项目编写一个 Spider 来爬取网站并提取数据使用命令行导出抓取到的数据改造 Spider使其递归跟随页面链接使用 Spider 命令行参数控制爬取行为。Scrapy 使用 Python 编写你对 Python 的掌握程度直接决定了能从 Scrapy 中挖掘多少价值。如果你是其他语言背景想快速上手 Python建议参考 Python 官方教程如果是编程初学者可以阅读Automate the Boring Stuff With Python、How To Think Like a Computer Scientist、Learn Python 3 The Hard Way等入门书籍。一、创建 Scrapy 项目开始抓取之前需要先搭建一个 Scrapy 项目。进入你希望存放代码的目录运行scrapy startproject tutorial这会在当前目录创建tutorial目录内容如下tutorial/ scrapy.cfg # 部署配置文件deploy configuration file tutorial/ # 项目的 Python 模块你的代码从这里被导入 __init__.py items.py # 项目 items 定义文件 middlewares.py # 项目中间件文件 pipelines.py # 项目管道文件 settings.py # 项目设置文件 spiders/ # 存放 spiders 的目录 __init__.py这份目录结构由仓库中的项目模板生成模板文件位于 scrapy/templates/project/其中 scrapy/templates/project/scrapy.cfg 定义了[settings]段指向项目名.settings设置模块和被注释掉的[deploy]段用于 Scrapy 部署各.py.tmpl文件则是生成items.py、middlewares.py、pipelines.py、settings.py的模板。爬取前先打开 settings.py设置 User-Agent在爬取任何内容之前教程建议打开settings.py并取消注释USER_AGENT一行标识你的爬虫身份例如项目名加上一个 URL 或邮箱地址。这样如果网站管理员对你的爬虫有意见他们可以联系你要求调整而不是直接封禁你。对应到当前仓库的模板 scrapy/templates/project/module/settings.py.tmpl模板生成的设置文件默认包含这些负责任地爬取相关的配置# Crawl responsibly by identifying yourself (and your website) on the user-agent #USER_AGENT $project_name (http://www.yourdomain.com) # Obey robots.txt rules ROBOTSTXT_OBEY True # Concurrency and throttling settings #CONCURRENT_REQUESTS 16 CONCURRENT_REQUESTS_PER_DOMAIN 1 DOWNLOAD_DELAY 1也就是说新项目默认遵守 robots.txt 规则、每个域名并发为 1、每次请求间隔 1 秒——这套保守的限速配置正是新手练习环境的安全底线。二、编写第一个 SpiderSpider 是你定义的类Scrapy 用它从网站或一组网站抓取信息。它必须继承scrapy.Spider定义初始要发出的请求并可选择地定义如何跟随页面链接、如何解析下载内容来提取数据。下面是第一个 Spider 的完整代码。把它保存为项目tutorial/spiders目录下的quotes_spider.pyfrom pathlib import Path import scrapy class QuotesSpider(scrapy.Spider): name quotes async def start(self): urls [ https://quotes.toscrape.com/page/1/, https://quotes.toscrape.com/page/2/, ] for url in urls: yield scrapy.Request(urlurl, callbackself.parse) def parse(self, response): page response.url.split(/)[-2] filename fquotes-{page}.html Path(filename).write_bytes(response.body) self.log(fSaved file {filename})这个 Spider 子类化scrapy.Spider定义了一些属性和方法name标识 Spider 的唯一名称。它必须在项目内唯一——不能给不同的 Spider 设置相同的 namestart必须是异步生成器产出让 Spider 开始爬取的请求以及可选的 items。后续请求将依次从这些初始请求派生出来。从源码注释看start()是 Scrapy 2.13 引入的写法见 Spider.start 的 docstring如果需要兼容更低版本可以额外定义一个返回可迭代对象的同步start_requests()方法parse处理每个请求下载完成后响应的方法。response参数是scrapy.http.TextResponse的实例持有页面内容并提供一系列处理方法。parse方法通常会解析响应把抓取的数据提取为 dict同时找到新的 URL 并据此创建新的scrapy.Request。源码补充当前版本中Spider.log()已被标记为弃用scrapy/spiders/init.py#L64-L76 中抛出ScrapyDeprecationWarning推荐使用self.logger例如self.logger.debug(fSaved file {filename})。运行 Spider进入项目顶层目录运行scrapy crawl quotes这条命令会运行我们刚添加的名为quotes的 Spider它会向quotes.toscrape.com域名发送若干请求。你会得到类似如下的输出... (omitted for brevity) 2016-12-16 21:24:05 [scrapy.core.engine] INFO: Spider opened 2016-12-16 21:24:05 [scrapy.extensions.logstats] INFO: Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0 items/min) 2016-12-16 21:24:05 [scrapy.extensions.telnet] DEBUG: Telnet console listening on 127.0.0.1:6023 2016-12-16 21:24:05 [scrapy.core.engine] DEBUG: Crawled (404) GET https://quotes.toscrape.com/robots.txt (referer: None) 2016-12-16 21:24:05 [scrapy.core.engine] DEBUG: Crawled (200) GET https://quotes.toscrape.com/page/1/ (referer: None) 2016-12-16 21:24:05 [scrapy.core.engine] DEBUG: Crawled (200) GET https://quotes.toscrape.com/page/2/ (referer: None) 2016-12-16 21:24:05 [quotes] DEBUG: Saved file quotes-1.html 2016-12-16 21:24:05 [quotes] DEBUG: Saved file quotes-2.html 2016-12-16 21:24:05 [scrapy.core.engine] INFO: Closing spider (finished) ...从日志可以读出几个细节引擎先请求了robots.txt对应模板中默认的ROBOTSTXT_OBEY True然后依次下载两页Spider 的parse把两个 HTML 文件写入当前目录。检查一下当前目录应该能看到新创建的quotes-1.html和quotes-2.html内容分别对应两个 URL——这正是parse方法指示的行为。如果你好奇为什么还没解析 HTML别急下面就会讲到。底层发生了什么Scrapy 发送Spider.start方法产出的第一个scrapy.Request对象。每当收到某个请求的响应Scrapy 就调用与该请求关联的回调方法本例中是parse并把scrapy.http.Response对象作为参数传入。在源码层面Spider._parse是默认回调的入口当请求没有显式指定 callback 时响应会回落到parsescrapy/spiders/init.py#L138-L164。start方法的快捷方式start_urls与其实现一个从 URL 产出scrapy.Request对象的start方法不如直接定义start_urls类属性给出一个 URL 列表。该列表会被start的默认实现用来为你的 Spider 创建初始请求from pathlib import Path import scrapy class QuotesSpider(scrapy.Spider): name quotes start_urls [ https://quotes.toscrape.com/page/1/, https://quotes.toscrape.com/page/2/, ] def parse(self, response): page response.url.split(/)[-2] filename fquotes-{page}.html Path(filename).write_bytes(response.body)虽然没有显式告诉 Scrapyparse方法仍然会被用来处理这些 URL 的每个请求——因为parse是 Scrapy 的默认回调方法会被调用处理所有没有显式分配 callback 的请求。从源码可以看到默认实现的本质scrapy/spiders/init.py#L89-L136async def start(self) - AsyncIterator[Any]: for url in self.start_urls: yield Request(url, dont_filterTrue)注意默认实现给起始请求加了dont_filterTrue即起始 URL 不受去重过滤器拦截保证每个 Spider 的入口页面一定被访问。三、使用 Scrapy Shell 提取数据学习如何用 Scrapy 提取数据最好的方式是打开 Scrapy Shell 动手尝试选择器scrapy shell https://quotes.toscrape.com/page/1/注意从命令行运行 Scrapy shell 时务必给 URL 加引号否则包含参数如字符的 URL 无法正常工作。在 Windows 上请改用双引号scrapy shell https://quotes.toscrape.com/page/1/。你会看到类似如下的输出[ ... Scrapy log here ... ] 2016-09-19 12:09:27 [scrapy.core.engine] DEBUG: Crawled (200) GET https://quotes.toscrape.com/page/1/ (referer: None) [s] Available Scrapy objects: [s] scrapy scrapy module (contains scrapy.Request, scrapy.Selector, etc) [s] crawler scrapy.crawler.Crawler object at 0x7fa91d888c90 [s] item {} [s] request GET https://quotes.toscrape.com/page/1/ [s] response 200 https://quotes.toscrape.com/page/1/ [s] settings scrapy.settings.Settings object at 0x7fa91d888c10 [s] spider DefaultSpider default at 0x7fa91c8af990 [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 browserShell 命令的实现在 scrapy/commands/shell.py它内部会创建一个真正的 Crawler 和下载引擎来处理 URL因此 shell 中拿到的response就是经过完整下载中间件处理后的真实响应。用 shell你可以用 CSS 配合response对象尝试选择元素 response.css(title) [Selector querydescendant-or-self::title datatitleQuotes to Scrape/title]运行response.css(title)的结果是一个名为SelectorList的类列表对象它表示一组scrapy.Selector对象的列表这些 Selector 包裹在 XML/HTML 元素外层让你可以执行进一步查询来细化选择或提取数据。要提取上面标题中的文本可以这样做 response.css(title::text).getall() [Quotes to Scrape]这里有两点值得注意其一我们在 CSS 查询中添加了::text表示只选择title元素内部的文本节点。如果不写::text得到的将是包含标签的完整 title 元素 response.css(title).getall() [titleQuotes to Scrape/title]其二.getall()的结果是一个列表选择器可能返回多个结果所以要把它们全部提取出来。当确定只要第一个结果时本例就是如此可以写 response.css(title::text).get() Quotes to Scrape等价写法是 response.css(title::text)[0].get() Quotes to Scrape对SelectorList实例按下标访问在没有结果时会抛出IndexError异常 response.css(noelement)[0].get() Traceback (most recent call last): ... IndexError: list index out of range更好的做法是直接在SelectorList实例上调用.get()——没有结果时它返回None response.css(noelement).get()这里有一课对于大多数抓取代码你希望它对页面上找不到内容这类错误有韧性这样即使某些部分抓取失败也至少能拿到部分数据。除了SelectorList的.getall()和.get()方法还可以用.re()方法配合正则表达式提取 response.css(title::text).re(rQuotes.*) [Quotes to Scrape] response.css(title::text).re(rQ\w) [Quotes] response.css(title::text).re(r(\w) to (\w)) [Quotes, Scrape]要找到合适的 CSS 选择器可以在 shell 中用view(response)把响应页面在浏览器中打开再用浏览器的开发者工具检查 HTML、构造选择器参见 开发者工具文档。Selector Gadget 也是一个好用的浏览器插件能快速为可视选中的元素定位 CSS 选择器。XPath 简介除 CSS 外Scrapy 选择器还支持 XPath 表达式 response.xpath(//title) [Selector query//title datatitleQuotes to Scrape/title] response.xpath(//title/text()).get() Quotes to ScrapeXPath 表达式非常强大是 Scrapy Selectors 的基石。事实上CSS 选择器在底层会被转换为 XPath——仔细读 shell 里 selector 对象的文本表示就能发现这一点如上面response.css(title)打印出的descendant-or-self::title。XPath 之所以更万能是因为它除了导航文档结构还能查看内容。用 XPath 你可以选出包含文字 Next Page 的那个链接这类目标。这使得 XPath 非常适合抓取任务即使你已经会写 CSS 选择器官方也鼓励你学习 XPath它会显著降低抓取难度。更多用法参见 Selectors 专题文档。提取名言与作者现在让我们完成 Spider 的提取代码。quotes.toscrape.com 上每条名言的 HTML 结构大致如下div classquote span classtext“The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking.”/span span by small classauthorAlbert Einstein/small a href/author/Albert-Einstein(about)/a /span div classtags Tags: a classtag href/tag/change/page/1/change/a a classtag href/tag/deep-thoughts/page/1/deep-thoughts/a a classtag href/tag/thinking/page/1/thinking/a a classtag href/tag/world/page/1/world/a /div /div打开 Scrapy Shell 玩一玩找到提取目标数据的方法scrapy shell https://quotes.toscrape.com用下面的查询可以得到名言 HTML 元素的选择器列表 response.css(div.quote) [Selector querydescendant-or-self::div[class and contains(concat( , normalize-space(class), ), quote )] datadiv classquote itemscope itemtype..., Selector querydescendant-or-self::div[class and contains(concat( , normalize-space(class), ), quote )] datadiv classquote itemscope itemtype..., ...]上面查询返回的每个选择器都可以继续在其子元素上运行进一步查询。把第一个选择器赋给变量就能针对某一条具体名言执行 CSS 查询 quote response.css(div.quote)[0]现在用quote对象提取text、author和tags text quote.css(span.text::text).get() text “The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking.” author quote.css(small.author::text).get() author Albert Einstein由于 tags 是一个字符串列表用.getall()取回全部 tags quote.css(div.tags a.tag::text).getall() tags [change, deep-thoughts, thinking, world]弄清每个字段的提取方式后就可以遍历所有 quote 元素把它们组装成 Python 字典 for quote in response.css(div.quote): ... text quote.css(span.text::text).get() ... author quote.css(small.author::text).get() ... tags quote.css(div.tags a.tag::text).getall() ... print(dict(texttext, authorauthor, tagstags)) ... {text: “The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking.”, author: Albert Einstein, tags: [change, deep-thoughts, thinking, world]} {text: “It is our choices, Harry, that show what we truly are, far more than our abilities.”, author: J.K. Rowling, tags: [abilities, choices]} ...把提取逻辑写进 Spider让我们回到 Spider。到目前为止它只把整个 HTML 页面存成了本地文件没有提取任何具体数据。现在把上面的提取逻辑整合进来。Scrapy Spider 通常会在回调中用yield关键字产出大量包含页面提取数据的字典import scrapy class QuotesSpider(scrapy.Spider): name quotes start_urls [ https://quotes.toscrape.com/page/1/, https://quotes.toscrape.com/page/2/, ] def parse(self, response): for quote in response.css(div.quote): yield { text: quote.css(span.text::text).get(), author: quote.css(small.author::text).get(), tags: quote.css(div.tags a.tag::text).getall(), }运行前先在 shell 中执行quit()退出然后scrapy crawl quotes此时它会通过日志输出提取到的数据2016-09-19 18:57:19 [scrapy.core.scraper] DEBUG: Scraped from 200 https://quotes.toscrape.com/page/1/ {tags: [life, love], author: André Gide, text: “It is better to be hated for what you are than to be loved for what you are not.”} 2016-09-19 18:57:19 [scrapy.core.scraper] DEBUG: Scraped from 200 https://quotes.toscrape.com/page/1/ {tags: [edison, failure, inspirational, paraphrased], author: Thomas A. Edison, text: “I have not failed. Ive just found 10,000 ways that wont work.”}四、保存抓取的数据保存抓取数据最简单的方式是使用 Feed Exportsscrapy crawl quotes -O quotes.json这会生成一个quotes.json文件包含全部抓取到的 items并以 JSON 格式序列化。命令行开关-O会覆盖已存在的文件如果想向已有文件追加内容应使用-o。但注意向 JSON 文件追加内容会使文件变成非法 JSON。追加时建议改用其他序列化格式例如 JSON Linesscrapy crawl quotes -o quotes.jsonlJSON Lines 格式之所以有用是因为它是流式的可以轻松追加新记录两次运行也不会像 JSON 那样产生格式问题。而且每条记录独占一行处理大文件时无需把全部内容载入内存JQ 之类的命令行工具就能逐行处理。对于本教程这样的小项目上面的方式已经足够。但如果你想对抓取的 items 做更复杂的处理可以编写 Item Pipeline。项目创建时已经为你准备好了 Item Pipeline 的占位文件tutorial/pipelines.py——不过如果只是想把 items 存下来并不一定需要实现任何 Item Pipeline。源码视角-o/-O选项由所有运行 Spider类命令的公共基类注册scrapy/commands/init.py#L197-L212支持在输出 URI 末尾加冒号指定格式如-o FILE:FORMATprocess_options会把它们汇总后写入FEEDS设置cmdline 优先级再由 FeedExporter 扩展落地。若 FeedExporter 未启用BaseRunSpiderCommand 还会主动打印一条警告提示不会有任何 items 被导出。五、跟随链接实现递归爬取假设你不想只抓前两页而想要 quotes.toscrape.com 全站的名言。既然已经会提取页面数据下面看看如何跟随页面链接。第一步是提取想要跟随的链接。检查页面可以看到下一页链接的标记如下ul classpager li classnext a href/page/2/Next span aria-hiddentruerarr;/span/a /li /ul在 shell 中试一下 response.css(li.next a).get() a href/page/2/Next span aria-hiddentrue→/span/a这拿到的是a元素但我们真正想要的是href属性。为此Scrapy 支持一种 CSS 扩展语法让你选择属性内容 response.css(li.next a::attr(href)).get() /page/2/另外还有attrib属性可用更多细节参见 选择器文档的 selecting-attributes 一节 response.css(li.next a).attrib[href] /page/2/下面是改造后的 Spider它会递归地跟随下一页链接并提取数据import scrapy class QuotesSpider(scrapy.Spider): name quotes start_urls [ https://quotes.toscrape.com/page/1/, ] def parse(self, response): for quote in response.css(div.quote): yield { text: quote.css(span.text::text).get(), author: quote.css(small.author::text).get(), tags: quote.css(div.tags a.tag::text).getall(), } next_page response.css(li.next a::attr(href)).get() if next_page is not None: next_page response.urljoin(next_page) yield scrapy.Request(next_page, callbackself.parse)数据提取完成后parse()方法会查找下一页链接用Response.urljoin方法链接可能是相对路径拼出完整绝对 URL然后产出指向下一页的新请求并把自身注册为回调来处理下一页的数据提取、让爬取继续推进到所有页面。这就是 Scrapy 的链接跟随机制当你在回调方法中 yield 一个 RequestScrapy 会调度发送该请求并注册回调方法在该请求完成时执行。借助它你可以构建出按自己定义的规则跟随链接、并根据访问的页面类型提取不同数据的复杂爬虫。在我们的例子里它形成了一个循环一直跟随下一页链接直到找不到为止——非常适合爬取博客、论坛和其他带分页的站点。创建 Request 的快捷方式response.follow创建 Request 对象有个快捷方式——response.followimport scrapy class QuotesSpider(scrapy.Spider): name quotes start_urls [ https://quotes.toscrape.com/page/1/, ] def parse(self, response): for quote in response.css(div.quote): yield { text: quote.css(span.text::text).get(), author: quote.css(span small::text).get(), tags: quote.css(div.tags a.tag::text).getall(), } next_page response.css(li.next a::attr(href)).get() if next_page is not None: yield response.follow(next_page, callbackself.parse)与scrapy.Request不同response.follow直接支持相对 URL——无需调用urljoin。注意response.follow只是返回一个 Request 实例你仍然需要 yield 这个 Request。从源码看scrapy/http/response/text.py#L180-L234follow的url参数除了字符串还可以是相对 URLscrapy.link.Link对象例如 链接提取器 的结果指向a/link元素的Selector例如response.css(a.my_link)[0]属性Selector单个而非 SelectorList例如response.css(a::attr(href))[0]。你还可以把选择器直接传给response.follow选择器会提取所需属性for href in response.css(ul.pager a::attr(href)): yield response.follow(href, callbackself.parse)对a元素还有进一步简写response.follow会自动使用其href属性for a in response.css(ul.pager a): yield response.follow(a, callbackself.parse)要从一个可迭代对象批量创建多个请求可以用response.follow_all源码实现anchors response.css(ul.pager a) yield from response.follow_all(anchors, callbackself.parse)或者进一步缩简——follow_all直接接受css/xpath参数yield from response.follow_all(cssul.pager a, callbackself.parse)更多示例与模式下面这个 Spider 演示了回调与链接跟随的另一个组合抓取作者信息。import scrapy class AuthorSpider(scrapy.Spider): name author start_urls [https://quotes.toscrape.com/] def parse(self, response): author_page_links response.css(.author a) yield from response.follow_all(author_page_links, self.parse_author) pagination_links response.css(li.next a) yield from response.follow_all(pagination_links, self.parse) def parse_author(self, response): def extract_with_css(query): return response.css(query).get(default).strip() yield { name: extract_with_css(h3.author-title::text), birthdate: extract_with_css(.author-born-date::text), bio: extract_with_css(.author-description::text), }这个 Spider 从主页出发跟随所有指向作者页面的链接并对每个调用parse_author回调同时跟随分页链接并复用parse回调与前文相同。这里把回调作为位置参数传给response.follow_all以缩短代码对scrapy.Request也适用。parse_author回调定义了一个辅助函数用 CSS 查询提取并清理数据get(default)保证选择不到时不抛异常然后 yield 出作者数据的 Python dict。这个 Spider 还展示了一个重要特性即使同一位作者有很多条名言也不需要担心多次访问同一个作者页面。Scrapy 默认会过滤掉指向已访问 URL 的重复请求避免因编程失误过度请求服务器。这一点由DUPEFILTER_CLASS设置控制默认实现是RfpDupeFilter其request_seen逻辑可参考 scrapy/dupefilters.py。至此你应该对 Scrapy 的链接跟随与回调机制有了不错的理解。如果想看一个更通用的例子可以研究scrapy.spiders.CrawlSpider类——它实现了一个小型规则引擎你可以在其之上编写自己的爬虫见 scrapy/spiders/crawl.py。另一个常见模式是用 向回调传递额外数据的技巧callback-data从多个页面组装出同一个 item。六、使用 Spider 命令行参数可以通过-a选项在运行 Spider 时向其传入命令行参数scrapy crawl quotes -O quotes-humor.json -a taghumor这些参数会被传给 Spider 的__init__方法并默认成为 Spider 的属性。本例中tag参数的值可以通过self.tag访问。利用它可以让 Spider 只抓取带特定 tag 的名言——根据参数构造 URLimport scrapy class QuotesSpider(scrapy.Spider): name quotes async def start(self): url https://quotes.toscrape.com/ tag getattr(self, tag, None) if tag is not None: url url tag/ tag yield scrapy.Request(url, self.parse) def parse(self, response): for quote in response.css(div.quote): yield { text: quote.css(span.text::text).get(), author: quote.css(small.author::text).get(), } next_page response.css(li.next a::attr(href)).get() if next_page is not None: yield response.follow(next_page, self.parse)给这个 Spider 传入taghumor参数后你会发现它只访问humor标签下的 URL例如https://quotes.toscrape.com/tag/humor。源码视角这条链路在代码中清晰可查——-a NAMEVALUE选项在 BaseRunSpiderCommand.add_options 中注册process_options用arglist_to_dict解析成字典后scrapy/commands/init.py#L214-L221最终经crawler_process.crawl(..., **opts.spargs)传入 Spider 构造函数scrapy/commands/crawl.py#L21-L32Spider.__init__中的self.__dict__.update(kwargs)一行scrapy/spiders/init.py#L47-L54则让这些参数自动变成实例属性——这正是默认成为 Spider 属性的实现来源。因此代码里用getattr(self, tag, None)防御式取值是标准写法未传参时属性不存在。关于处理 Spider 参数的更多细节类型转换、验证等参见 Spider 专题文档。七、下一步本教程只覆盖了 Scrapy 的基础还有大量特性没有展开。可以查看 概览章节 中还能做什么topics-whatelse部分快速了解最重要的进阶特性也可以从该章节的基础篇继续深入学习命令行工具、Spider、选择器以及教程未涉及的内容如如何对抓取数据建模。如果想动手玩一个示例项目可以看 示例章节。附本篇涉及的关键仓库文件速查主题仓库路径教程原文docs/intro/tutorial.rstSpider 基类start/parse 默认实现scrapy/spiders/init.pyresponse.follow/follow_allscrapy/http/response/text.pycrawl命令scrapy/commands/crawl.py-a/-o/-O/-s选项定义scrapy/commands/init.pyScrapy Shell 命令scrapy/commands/shell.py项目模板scrapy.cfg、settings.py 等scrapy/templates/project/请求去重过滤器scrapy/dupefilters.py【免费下载链接】scrapyScrapy, a fast high-level web crawling scraping framework for Python.项目地址: https://gitcode.com/GitHub_Trending/sc/scrapy创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表