Lzh on GitHub

Frequently Asked Questions (常见问题)

How does Scrapy compare to BeautifulSoup or lxml? (Scrapy 与 BeautifulSoup 或 lxml 相比如何?)

BeautifulSouplxml 是用于解析 HTML 和 XML 的库。Scrapy 是一个应用程序框架,用于编写抓取网站并从中提取数据的 Web 爬虫。

Scrapy 提供了一个内置的数据提取机制(称为选择器),但如果您觉得使用 BeautifulSoup(或 lxml)更舒服,可以轻松地使用它们。毕竟,它们只是可以从任何 Python 代码导入和使用的解析库。

换句话说,将 BeautifulSoup(或 lxml)与 Scrapy 进行比较,就像将 jinja2Django 进行比较一样。

Can I use Scrapy with BeautifulSoup? (我可以使用 Scrapy 和 BeautifulSoup 吗?)

是的,可以。如上所述BeautifulSoup 可以用于在 Scrapy 回调中解析 HTML 响应。您只需将响应主体传递给 BeautifulSoup 对象,然后从中提取所需的任何数据。

这是一个使用 BeautifulSoup API 的爬虫示例,使用 lxml 作为 HTML 解析器:

from bs4 import BeautifulSoup
import scrapy

class ExampleSpider(scrapy.Spider):
    name = "example"
    allowed_domains = ["example.com"]
    start_urls = ("http://www.example.com/",)

    def parse(self, response):
        # 使用 lxml 以获得体面的 HTML 解析速度
        soup = BeautifulSoup(response.text, "lxml")
        yield {"url": response.url, "title": soup.h1.string}

注意

BeautifulSoup 支持多种 HTML/XML 解析器。请参阅 BeautifulSoup 的官方文档,了解哪些可用。

Did Scrapy “steal” X from Django? (Scrapy “窃取”了 Django 的 X 吗?)

可能吧,但我们不喜欢这个词。我们认为 Django 是一个很棒的开源项目,也是一个值得效仿的榜样,所以我们将其作为 Scrapy 的灵感来源。

我们相信,如果某件事已经做得很好,就没有必要重新发明。这个概念不仅是开源和自由软件的基础之一,而且不仅适用于软件,还适用于文档、程序、政策等。因此,我们没有亲自解决每个问题,而是选择从那些已经妥善解决问题的项目中复制想法,并专注于我们需要解决的实际问题。

如果 Scrapy 能为其他项目提供灵感,我们将感到自豪。请随意从我们这里“窃取”!

Does Scrapy work with HTTP proxies? (Scrapy 支持 HTTP 代理吗?)

是的。通过 HTTP 代理下载器中间件提供了对 HTTP 代理的支持(自 Scrapy 0.8 起)。请参阅 HttpProxyMiddleware

How can I scrape an item with attributes in different pages? (如何在不同页面中抓取具有属性的项目?)

请参阅向回调函数传递附加数据

How can I simulate a user login in my spider? (如何在我的爬虫中模拟用户登录?)

请参阅使用 FormRequest.from_response() 模拟用户登录

Does Scrapy crawl in breadth-first or depth-first order? (Scrapy 是按广度优先还是深度优先顺序抓取?)

默认是 DFO(深度优先),但也可以是其他顺序。

My Scrapy crawler has memory leaks. What can I do? (我的 Scrapy 爬虫有内存泄漏。我能做什么?)

请参阅调试内存泄漏

此外,Python 存在一个内置的内存泄漏问题,在无泄漏的泄漏中有所描述。

How can I make Scrapy consume less memory? (如何让 Scrapy 消耗更少的内存?)

请参阅上一个问题。

How can I prevent memory errors due to many allowed domains? (如何防止由于许多允许的域导致的内存错误?)

如果您有一个爬虫,其中 allowed_domains 列表很长(例如 50,000+),请考虑用一个自定义下载器中间件替换默认的 OffsiteMiddleware 下载器中间件,该中间件需要的内存更少。例如:

  • 如果您的域名足够相似,请使用您自己的正则表达式,而不是将 allowed_domains 中的字符串连接成复杂的正则表达式。
  • 如果您可以满足安装要求,请使用 pyre2 而不是 Python 的 re 来编译您的 URL 过滤正则表达式。请参阅 issue 1908
  • 另请参阅 StackOverflow 上的其他建议

注意

记住在启用自定义实现时禁用 scrapy.downloadermiddlewares.offsite.OffsiteMiddleware

DOWNLOADER_MIDDLEWARES = {
    "scrapy.downloadermiddlewares.offsite.OffsiteMiddleware": None,
    "myproject.middlewares.CustomOffsiteMiddleware": 50,
}

Can I use Basic HTTP Authentication in my spiders? (我可以在我的爬虫中使用基本 HTTP 身份验证吗?)

是的,请参阅 HttpAuthMiddleware

Why does Scrapy download pages in English instead of my native language? (为什么 Scrapy 下载的页面是英文而不是我的母语?)

尝试通过覆盖 DEFAULT_REQUEST_HEADERS 设置来更改默认的 Accept-Language 请求头。

Where can I find some example Scrapy projects? (我在哪里可以找到一些 Scrapy 项目示例?)

请参阅示例

Can I run a spider without creating a project? (我可以不创建项目就运行爬虫吗?)

是的。您可以使用 runspider 命令。例如,如果您有一个用 my_spider.py 文件编写的爬虫,您可以使用以下命令运行它:

scrapy runspider my_spider.py

有关更多信息,请参阅 runspider 命令。

I get “Filtered offsite request” messages. How can I fix them? (我收到“Filtered offsite request”消息。如何解决?)

这些消息(以 DEBUG 级别记录)不一定意味着存在问题,因此您可能不需要修复它们。

这些消息由 OffsiteMiddleware 抛出,这是一个下载器中间件(默认启用),其目的是过滤掉对爬虫覆盖范围之外的域的请求。

请参阅部署爬虫

Can I use JSON for large exports? (我可以使用 JSON 进行大量导出吗?)

这将取决于您的输出有多大。请参阅 JsonItemExporter 文档中的此警告

Can I return (Twisted) deferreds from signal handlers? (我可以从信号处理程序返回(Twisted)deferreds 吗?)

有些信号支持从其处理程序返回 deferreds,有些不支持。请参阅内置信号参考以了解哪些信号支持。

What does the response status code 999 mean? (响应状态码 999 是什么意思?)

999 是 Yahoo 网站用于限制请求的自定义响应状态码。尝试通过在爬虫中使用 2(或更高)的下载延迟来减慢抓取速度:

from scrapy.spiders import CrawlSpider

class MySpider(CrawlSpider):
    name = "myspider"

    download_delay = 2

    # [ ... rest of the spider code ... ]

或者通过使用 DOWNLOAD_DELAY 设置在项目中设置全局下载延迟。

Can I call pdb.set_trace() from my spiders to debug them? (我可以在我的爬虫中调用 pdb.set_trace() 来调试它们吗?)

是的,但您也可以使用 Scrapy shell,它允许您快速分析(甚至修改)爬虫正在处理的响应,这通常比普通的 pdb.set_trace() 更有用。

有关更多信息,请参阅从爬虫调用 shell 以检查响应

Simplest way to dump all my scraped items into a JSON/CSV/XML file? (将所有抓取到的项目转储到 JSON/CSV/XML 文件中最简单的方法是什么?)

转储到 JSON 文件:

scrapy crawl myspider -O items.json

转储到 CSV 文件:

scrapy crawl myspider -O items.csv

转储到 XML 文件:

scrapy crawl myspider -O items.xml

有关更多信息,请参阅馈送导出

What’s this huge cryptic __VIEWSTATE parameter used in some forms? (某些表单中使用的这个巨大而神秘的 __VIEWSTATE 参数是什么?)

__VIEWSTATE 参数用于使用 ASP.NET/VB.NET 构建的网站。有关其工作原理的更多信息,请参阅此页面。此外,这里有一个爬虫示例,它抓取了其中一个网站。

What’s the best way to parse big XML/CSV data feeds? (解析大型 XML/CSV 数据馈送的最佳方法是什么?)

使用 XPath 选择器解析大型馈送可能会出现问题,因为它们需要将整个馈送的 DOM 构建到内存中,这可能会非常慢并消耗大量内存。

为了避免一次性将整个馈送解析到内存中,您可以使用 xmliter_lxml()csviter() 函数。实际上,XMLFeedSpider 就是使用它们。

scrapy.utils.iterators.xmliter_lxml(obj: Response | str | bytes, nodename: str, namespace: str | None = None, prefix: str = 'x') -> Iterator[Selector][source]

scrapy.utils.iterators.csviter(obj: Response | str | bytes, delimiter: str | None = None, headers: list[str] | None = None, encoding: str | None = None, quotechar: str | None = None) -> Iterator[dict[str, str]][source]

从给定的 CSV 对象返回字典迭代器。

obj 可以是:

  • 一个 Response 对象
  • 一个 unicode 字符串
  • 一个 utf-8 编码的字符串

delimiter 是用于分隔给定 obj 中字段的字符。 headers 是一个可迭代对象,如果提供,则为返回的字典提供键,否则使用第一行。 quotechar 是用于包围给定 obj 中字段的字符。

是的,Scrapy 会接收并跟踪服务器发送的 cookie,并在后续请求中将其发送回去,就像任何常规 Web 浏览器一样。

有关更多信息,请参阅请求和响应CookiesMiddleware

启用 COOKIES_DEBUG 设置。

How can I instruct a spider to stop itself? (如何指示爬虫停止自身?)

从回调中抛出 CloseSpider 异常。有关更多信息,请参阅:CloseSpider

How can I prevent my Scrapy bot from getting banned? (如何防止我的 Scrapy 机器人被禁止?)

请参阅避免被禁止

Should I use spider arguments or settings to configure my spider? (我应该使用爬虫参数还是设置来配置我的爬虫?)

爬虫参数设置都可以用来配置您的爬虫。没有严格的规则强制使用其中一个,但设置更适合那些一旦设置就不太会改变的参数,而爬虫参数则意味着更频繁地改变,甚至每次爬虫运行时都会改变,有时甚至是爬虫运行的必要条件(例如,设置爬虫的起始 URL)。

举例说明,假设您有一个爬虫需要登录网站才能抓取数据,并且您只想抓取网站的特定部分数据(每次都不同)。在这种情况下,登录凭据将是设置,而要抓取的部分的 URL 将是爬虫参数。

I’m scraping a XML document and my XPath selector doesn’t return any items (我正在抓取 XML 文档,但我的 XPath 选择器未返回任何项目)

您可能需要删除命名空间。请参阅删除命名空间

How to split an item into multiple items in an item pipeline? (如何在项目管道中将一个项目拆分为多个项目?)

项目管道不能为每个输入项目生成多个项目。请创建一个爬虫中间件,并使用其 process_spider_output() 方法来实现此目的。例如:

from copy import deepcopy
from itemadapter import ItemAdapter
from scrapy import Request

class MultiplyItemsMiddleware:
    def process_spider_output(self, response, result, spider):
        for item_or_request in result:
            if isinstance(item_or_request, Request):
                continue
            adapter = ItemAdapter(item)
            for _ in range(adapter["multiply_by"]):
                yield deepcopy(item)

Does Scrapy support IPv6 addresses? (Scrapy 支持 IPv6 地址吗?)

是的,通过将 DNS_RESOLVER 设置为 scrapy.resolver.CachingHostnameResolver。请注意,这样做会失去为 DNS 请求设置特定超时(DNS_TIMEOUT 设置的值将被忽略)的能力。

How to deal with <class 'ValueError'>: filedescriptor out of range in select() exceptions? (如何处理 <class 'ValueError'>: filedescriptor out of range in select() 异常?)

此问题已被报告在 macOS 上运行大规模抓取时出现,其中默认的 Twisted reactor 是 twisted.internet.selectreactor.SelectReactor。可以通过使用 TWISTED_REACTOR 设置切换到不同的 reactor。

How can I cancel the download of a given response? (如何取消给定响应的下载?)

在某些情况下,停止下载特定响应可能很有用。例如,有时您可以通过检查响应的标头或其主体的前几个字节来确定是否需要响应的完整内容。在这种情况下,您可以通过将处理程序附加到 bytes_receivedheaders_received 信号并抛出 StopDownload 异常来节省资源。请参阅停止下载响应主题以获取更多信息和示例。

How can I make a blank request? (如何发起一个空白请求?)

from scrapy import Request
blank_request = Request("data:,")

在这种情况下,URL 设置为数据 URI 方案。数据 URL 允许您在网页中内联包含数据,类似于外部资源。“data:”方案与空内容(“,”)实际上创建了一个对没有特定内容的 data URL 的请求。

Running runspider I get error: No spider found in file: <filename> (运行 runspider 时我收到 error: No spider found in file: <filename>)

如果您的 Scrapy 项目中有一个爬虫模块的名称与某个 Python 标准库模块(例如 csv.pyos.py)或您安装的任何 Python 包的名称冲突,则可能会发生这种情况。请参阅 issue 2680