常见问题
Scrapy 与 BeautifulSoup 或 lxml 有何区别?
BeautifulSoup 和 lxml 是用于解析 HTML 和 XML 的库。Scrapy 是一个用于编写网络爬虫的应用程序框架,用于爬取网站并从中提取数据。
Scrapy 提供了一个内置的数据提取机制(称为 选择器),但如果您更习惯使用 BeautifulSoup(或 lxml),则可以轻松地使用它们。毕竟,它们只是解析库,可以从任何 Python 代码中导入和使用。
换句话说,将 BeautifulSoup(或 lxml)与 Scrapy 进行比较,就像将 jinja2 与 Django 进行比较一样。
我可以在 Scrapy 中使用 BeautifulSoup 吗?
是的,可以。如 上文 所述,可以在 Scrapy 回调函数中使用 BeautifulSoup 解析 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 代理吗?
是的。Scrapy 通过 HTTP 代理下载器中间件(自 Scrapy 0.8 起支持)提供 HTTP 代理支持。请参阅 HttpProxyMiddleware
。
如何从不同页面中爬取具有不同属性的数据项?
请参阅 向回调函数传递额外数据。
如何在爬虫中模拟用户登录?
Scrapy 是按广度优先还是深度优先顺序爬取?
我的 Scrapy 爬虫有内存泄漏。我该怎么办?
请参阅 调试内存泄漏。
此外,Python 本身也存在一个内存泄漏问题,在 Leaks without leaks 中有所描述。
如何让 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,
}
我可以在爬虫中使用基本 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 是雅虎网站用来限制请求的自定义响应状态码。尝试在您的爬虫中使用下载延迟 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
有关更多信息,请参阅 导出数据源
一些表单中使用的那个巨大而神秘的 __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 是用于分隔给定对象中的字段的字符。
headers 是一个可迭代对象,如果提供,则为返回的字典提供键;否则,使用第一行作为键。
quotechar 是用于封闭给定对象中的字段的字符。
如何指示爬虫停止运行?
从回调函数中引发 CloseSpider
异常。有关更多信息,请参阅:CloseSpider
。
如何防止我的 Scrapy 机器人被封禁?
请参阅 避免被封禁。
我应该使用爬虫参数还是设置来配置我的爬虫?
爬虫参数 和 设置 都可以用来配置您的爬虫。没有严格的规则强制使用哪个,但设置更适合那些一旦设定后不太会改变的参数,而爬虫参数则意味着更频繁地改变,甚至在每次爬虫运行时都会改变,有时甚至是爬虫运行所必需的(例如,设置爬虫的起始 URL)。
举个例子,假设您有一个爬虫需要登录网站才能爬取数据,并且只想爬取网站的某个特定部分的数据(每次都不同)。在这种情况下,登录凭据将是设置,而要爬取的部分的 URL 将是爬虫参数。
我正在爬取 XML 文档,但我的 XPath 选择器没有返回任何数据项
您可能需要移除命名空间。请参阅 移除命名空间。
如何在数据项管道中将一个数据项分割成多个数据项?
数据项管道 不能为每个输入项生成多个数据项。请改用 创建爬虫中间件,并使用其 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)
Scrapy 支持 IPv6 地址吗?
是的,通过将 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。