常见问题
Scrapy 与 BeautifulSoup 或 lxml 相比如何?
BeautifulSoup 和 lxml 是用于解析 HTML 和 XML 的库。Scrapy 是一个应用程序框架,用于编写抓取网站并从中提取数据的网络爬虫。
Scrapy 提供了一种内置的数据提取机制(称为选择器),但如果您更习惯使用 BeautifulSoup(或 lxml),也可以轻松地使用它们。毕竟,它们只是解析库,可以从任何 Python 代码中导入和使用。
换句话说,将 BeautifulSoup(或 lxml)与 Scrapy 进行比较,就像将 jinja2 与 Django 进行比较一样。
我可以使用 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):
# use lxml to get decent HTML parsing speed
soup = BeautifulSoup(response.text, "lxml")
yield {"url": response.url, "title": soup.h1.string}
注意
BeautifulSoup 支持多种 HTML/XML 解析器。请参阅 BeautifulSoup 的官方文档,了解可用的解析器。
Scrapy 是否“借鉴”了 Django 的 X?
可能吧,但我们不喜欢那个词。我们认为 Django 是一个很棒的开源项目,也是一个值得效仿的典范,所以我们将其作为 Scrapy 的灵感来源。
我们认为,如果某件事情已经做得很好,就没有必要重新发明。这个概念,除了是开源和自由软件的基础之一外,不仅适用于软件,也适用于文档、程序、政策等。因此,我们选择从那些已经很好地解决问题的项目中借鉴想法,而不是亲自去解决每一个问题,从而专注于我们需要解决的真正问题。
如果 Scrapy 能为其他项目提供灵感,我们会感到自豪。欢迎借鉴我们的思想!
Scrapy 支持 HTTP 代理吗?
是的。HTTP 代理支持通过 HTTP Proxy 下载器中间件提供。请参阅 HttpProxyMiddleware。
Scrapy 支持 SOCKS 代理吗?
是的,当使用 HttpxDownloadHandler 时支持。请参阅 HttpProxyMiddleware 和处理程序文档。
如何抓取属性分散在不同页面的项目?
请参阅将额外数据传递给回调函数。
如何在我的爬虫中模拟用户登录?
Scrapy 是广度优先还是深度优先爬取?
我的 Scrapy 爬虫存在内存泄漏。我该怎么办?
请参阅调试内存泄漏。
此外,Python 存在一个内置的内存泄漏问题,在无泄漏的泄漏中有描述。
如何让 Scrapy 消耗更少的内存?
请参阅上一个问题。
如何防止因许多允许域导致的内存错误?
如果您的爬虫有一个很长的 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,
}
我可以在爬虫中使用 Basic HTTP 认证吗?
是的,请参阅 HttpAuthMiddleware。
为什么 Scrapy 下载的页面是英文而不是我的母语?
尝试通过覆盖 DEFAULT_REQUEST_HEADERS 设置来更改默认的 Accept-Language 请求头。
我在哪里可以找到一些 Scrapy 项目示例?
请参阅示例。
我可以在不创建项目的情况下运行爬虫吗?
是的。您可以使用 runspider 命令。例如,如果您的爬虫写在 my_spider.py 文件中,您可以这样运行它
scrapy runspider my_spider.py
有关更多信息,请参阅 runspider 命令。
我收到“Filtered offsite request”消息。如何解决?
这些消息(以 DEBUG 级别记录)不一定意味着存在问题,因此您可能不需要修复它们。
这些消息由 OffsiteMiddleware 抛出,它是一个下载器中间件(默认启用),其目的是过滤掉对爬虫覆盖范围之外的域的请求。
在生产环境中部署 Scrapy 爬虫的推荐方法是什么?
请参阅部署爬虫。
我可以使用 JSON 进行大型导出吗?
这将取决于您的输出有多大。请参阅 此警告 在 JsonItemExporter 文档中。
我可以从信号处理程序返回 (Twisted) deferreds 吗?
有些信号支持从其处理程序返回 deferreds,有些则不支持。请参阅内置信号参考以了解具体情况。
响应状态码 999 是什么意思?
999 是 Yahoo 网站用于限制请求的自定义响应状态码。尝试在您的爬虫中使用 2(或更高)的下载延迟来降低抓取速度
from scrapy.spiders import CrawlSpider
class MySpider(CrawlSpider):
name = "myspider"
download_delay = 2
# [ ... rest of the spider code ... ]
或者通过 DOWNLOAD_DELAY 设置在项目中设置全局下载延迟。
我可以在爬虫中调用 pdb.set_trace() 来调试它们吗?
是的,但您也可以使用 Scrapy shell,它允许您快速分析(甚至修改)爬虫正在处理的响应,这通常比普通的 pdb.set_trace() 更有用。
有关更多信息,请参阅从爬虫调用 shell 以检查响应。
将所有抓取到的项目导出到 JSON/CSV/XML 文件的最简单方法是什么?
导出到 JSON 文件
scrapy crawl myspider -O items.json
导出到 CSV 文件
scrapy crawl myspider -O items.csv
导出到 XML 文件
scrapy crawl myspider -O items.xml
有关更多信息,请参阅Feed 导出
某些表单中使用的这个巨大且神秘的 __VIEWSTATE 参数是什么?
__VIEWSTATE 参数用于使用 ASP.NET/VB.NET 构建的网站。有关其工作原理的更多信息,请参阅此页面。此外,这里有一个抓取此类网站的示例爬虫。
解析大型 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 中字段的字符。
如何让爬虫自行停止?
从回调中抛出 CloseSpider 异常。有关更多信息,请参阅:CloseSpider。
如何防止我的 Scrapy 机器人被封禁?
请参阅避免被封禁。
我应该使用爬虫参数还是设置来配置我的爬虫?
爬虫参数和设置都可以用来配置您的爬虫。没有严格的规则强制使用其中一个,但设置更适合那些一旦设置就不太会改变的参数,而爬虫参数则意味着更频繁地改变,甚至在每次爬虫运行时都会改变,有时甚至是爬虫运行所必需的(例如,设置爬虫的起始 URL)。
举例说明,假设您有一个爬虫需要登录网站才能抓取数据,并且您只想抓取网站某个特定部分的数据(每次都不同)。在这种情况下,登录凭据将是设置,而要抓取的部分的 URL 将是爬虫参数。
我正在抓取 XML 文档,但我的 XPath 选择器没有返回任何项目
您可能需要移除命名空间。请参阅移除命名空间。
如何在 Item Pipeline 中将一个项目拆分成多个项目?
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):
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)
Scrapy 支持 IPv6 地址吗?
是的,但当使用 HTTP11DownloadHandler 或 H2DownloadHandler 时,您需要将 TWISTED_DNS_RESOLVER 设置为 scrapy.resolver.CachingHostnameResolver。请注意,这样做您将失去为 DNS 请求设置特定超时(DNS_TIMEOUT 设置的值将被忽略)的能力。
如何处理 <class 'ValueError'>: filedescriptor out of range in select() 异常?
据报道,当在 macOS 上运行大规模抓取时会出现此问题,其中默认的 Twisted reactor 是 twisted.internet.selectreactor.SelectReactor。通过使用 TWISTED_REACTOR 设置可以切换到不同的 reactor。
如何取消给定响应的下载?
在某些情况下,停止下载某个响应可能会很有用。例如,有时您可以通过检查其标头或正文的开头字节来确定是否需要响应的全部内容。在这种情况下,您可以通过将处理程序附加到 bytes_received 或 headers_received 信号并抛出 StopDownload 异常来节省资源。请参阅停止下载响应主题以获取更多信息和示例。
如何发起一个空白请求?
from scrapy import Request
blank_request = Request("data:,")
在这种情况下,URL 设置为数据 URI 方案。数据 URL 允许您在网页中内联包含数据,类似于外部资源。带有空内容(“,”)的“data:”方案本质上是创建一个对没有特定内容的数据 URL 的请求。
运行 runspider 时我收到 error: No spider found in file: <filename> 错误
如果您的 Scrapy 项目中的爬虫模块名称与 Python 标准库模块(例如 csv.py 或 os.py)的名称,或您安装的任何 Python 包的名称冲突,则可能会发生这种情况。请参阅 issue 2680。