Scrapy是一款强大的网络爬虫框架,广泛用于数据抓取和解析。本文详细介绍了Scrapy的安装步骤、项目配置、爬取规则、中间件与管道的使用方法,并提供了实战案例和常见问题的解答,帮助读者更好地理解和使用Scrapy。
Scrapy 是一款用于从网站中抓取数据的强大框架,主要用于构建网络爬虫,以从网页中提取结构化数据。它使用 Python 编写,具有高度可扩展性和灵活性。Scrapy 使用异步、非阻塞的网络爬取方法,使其能够在较少资源的情况下快速抓取大量数据。Scrapy 是一个开源项目,用于构建爬虫以抓取网站并解析数据。它主要用于数据挖掘、信息收集、网络监测等场景。
Scrapy 提供了强大的功能,例如:
安装 Scrapy 需要 Python 环境,一般推荐使用最新版本的 Python 3。以下是安装步骤:
安装 Python 环境
如果您还没有安装 Python,可以从官网下载最新版本的 Python,并按照官方文档进行安装。在安装过程中,请确保选择添加 Python 到 PATH,这样可以在命令行中直接使用 Python。
安装 Scrapy
打开命令行工具,输入以下命令安装 Scrapy:
pip install scrapy
验证安装
安装完成后,可以通过以下命令验证 Scrapy 是否安装成功:
scrapy --version
如果安装成功,会显示 Scrapy 的版本号。
安装相关依赖库
某些功能可能需要额外的依赖库。例如,安装 lxml 和 cssselect 可以提高选择器的性能:
pip install lxml cssselect
pip install scrapyshell
创建Scrapy项目后,可以使用 Scrapy Shell 来验证选择器是否能正确提取所需的数据。
创建 Scrapy 项目的步骤如下:
创建项目
使用命令行工具(如命令提示符或终端),执行以下命令来创建一个新的 Scrapy 项目:
scrapy startproject myproject
这条命令会在当前目录下创建一个名为 myproject
的文件夹,并自动生成一些基本文件和目录结构。项目的基本结构如下:
myproject/ ├── myproject/ │ ├── __init__.py │ ├── items.py │ ├── middlewares.py │ ├── pipelines.py │ ├── settings.py │ └── spiders/ │ ├── __init__.py │ └── firstSpider.py └── scrapy.cfg
创建爬虫
在项目的 myproject/spiders
目录下,创建一个新的爬虫文件。例如,创建一个名为 firstSpider.py
的文件,并在其中定义一个新的爬虫:
import scrapy class FirstSpiderSpider(scrapy.Spider): name = 'firstSpider' allowed_domains = ['example.com'] start_urls = ['http://example.com/'] def parse(self, response): pass
这个爬虫将从 example.com
开始抓取数据。
scrapy crawl firstSpider
Scrapy 提供了一种灵活的方式来配置爬虫的行为。以下是一些常见的配置项:
设置元信息
可以在 settings.py
文件中设置爬虫的元信息。例如,设置爬虫的名称、延迟时间、用户代理等:
BOT_NAME = 'myproject' SPIDER_MODULES = ['myproject.spiders'] NEWSPIDER_MODULE = 'myproject.spiders' # 限制下载延迟 DOWNLOAD_DELAY = 1 # 设置用户代理 USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36' # 启用的中间件 DOWNLOADER_MIDDLEWARES = { 'myproject.middlewares.MyCustomDownloaderMiddleware': 543, } # 启用的管道 ITEM_PIPELINES = { 'myproject.pipelines.MyPipeline': 300, }
定义请求
在爬虫文件中,定义 start_urls
和 parse
方法:
import scrapy class ExampleSpider(scrapy.Spider): name = 'example' allowed_domains = ['example.com'] start_urls = ['http://example.com/'] def parse(self, response): # 在这里处理响应 pass
parse
方法中,可以使用各种方法来处理 HTTP 响应。例如,使用 response.css
或 response.xpath
提取数据。Scrapy 使用选择器来解析和提取数据。选择器通过 XPath 或 CSS 选择器来定位网页中的特定部分,从而提取所需的数据。以下是使用选择器的示例:
使用 CSS 选择器
CSS 选择器是用于选择 DOM 元素的简洁语法,类似于浏览器开发者工具中的选择器。例如,提取页面中的所有链接:
links = response.css('a::attr(href)').getall()
使用 XPath 选择器
XPath 是一种强大的查询语言,用于遍历 XML 和 HTML 文档。例如,提取页面中的所有链接:
links = response.xpath('//a/@href').getall()
提取文本
除了提取链接,还可以提取文本内容。例如,提取页面中的所有段落:
paragraphs = response.css('p::text').getall()
response.urljoin
方法可以将相对路径转换为绝对路径:
absolute_url = response.urljoin(link)
假设我们需要从 example.com
抓取新闻标题和链接,创建一个新的 Scrapy 项目 news_scraper
:
scrapy startproject news_scraper
在 news_scraper/spiders
目录下,创建一个名为 news_spider.py
的文件:
import scrapy class NewsSpider(scrapy.Spider): name = 'news' allowed_domains = ['example.com'] start_urls = ['http://example.com/news'] def parse(self, response): for article in response.css('div.article'): title = article.css('h2.title::text').get() link = article.css('a::attr(href)').get() yield { 'title': title, 'link': link, } next_page = response.css('a.next::attr(href)').get() if next_page is not None: yield response.follow(next_page, self.parse)
在 settings.py
中,设置一些基本配置:
DOWNLOAD_DELAY = 1 USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36'
运行爬虫:
scrapy crawl news
Scrapy 选择器使用 XPath 和 CSS 选择器来提取数据,以下是示例代码:
CSS 选择器示例
# 提取所有段落的文本 paragraphs = response.css('p::text').getall() # 提取所有链接的 href 属性 links = response.css('a::attr(href)').getall()
XPath 选择器示例
# 提取所有段落的文本 paragraphs = response.xpath('//p/text()').getall() # 提取所有链接的 href 属性 links = response.xpath('//a/@href').getall()
getall
,还可以使用 get
方法来获取第一个匹配结果:
first_paragraph = response.css('p::text').get() first_link = response.css('a::attr(href)').get()
Scrapy 中间件提供了扩展框架功能的能力,可以在请求和响应通过 Scrapy 处理过程中进行拦截和修改。以下是中间件的主要应用场景:
设置请求头
可以在中间件中设置请求头,如 User-Agent、Cookies 等:
class UserAgentMiddleware(object): def process_request(self, request, spider): request.headers['User-Agent'] = 'Mozilla/5.0'
处理 Cookies
可以在中间件中设置和处理 Cookies:
class CookieMiddleware(object): def process_request(self, request, spider): request.cookies['session'] = '123456'
下载器中间件
下载器中间件在请求和响应之间起作用,可以对请求和响应进行自定义处理。例如,添加代理服务器或设置请求头:
class MyDownloaderMiddleware(object): def process_request(self, request, spider): # 添加代理服务器 request.meta['proxy'] = 'http://proxy.example.com' return request
蜘蛛中间件
蜘蛛中间件在蜘蛛处理请求和响应时介入,例如在请求被调度前或响应被处理前做一些额外的操作:
class MySpiderMiddleware(object): def process_request(self, request, spider): # 在请求发送前做一些操作 return None def process_response(self, response, request, spider): # 在响应处理前做一些操作 return response
假设我们需要在请求中加入一个固定的 User-Agent,可以在 myproject/middlewares.py
文件中定义一个中间件:
class UserAgentMiddleware(object): def process_request(self, request, spider): request.headers['User-Agent'] = 'Mozilla/5.0'
在 settings.py
文件中启用该中间件:
DOWNLOADER_MIDDLEWARES = { 'myproject.middlewares.UserAgentMiddleware': 543, }
管道(Pipelines)是 Scrapy 中用于处理和存储提取的数据的重要组件。例如,将数据保存到数据库、文件系统等。以下是管道的主要作用和配置方法:
定义管道
在 myproject/pipelines.py
文件中定义管道类:
class MyPipeline(object): def process_item(self, item, spider): # 处理 item 数据 return item
启用管道
在 settings.py
文件中启用管道:
ITEM_PIPELINES = { 'myproject.pipelines.MyPipeline': 300, }
保存到数据库
例如,使用 SQLite 数据库保存数据:
import sqlite3 class SqlitePipeline(object): def __init__(self): self.conn = sqlite3.connect('data.db') self.c = self.conn.cursor() self.c.execute('''CREATE TABLE IF NOT EXISTS items (title text, link text)''') def process_item(self, item, spider): self.c.execute("INSERT INTO items VALUES (?, ?)", (item['title'], item['link'])) self.conn.commit() return item def close_spider(self, spider): self.conn.close()
假设我们需要将抓取的数据保存到 SQLite 数据库,可以在 myproject/pipelines.py
文件中定义一个管道:
import sqlite3 class SqlitePipeline(object): def __init__(self): self.conn = sqlite3.connect('data.db') self.c = self.conn.cursor() self.c.execute('''CREATE TABLE IF NOT EXISTS items (title text, link text)''') def process_item(self, item, spider): self.c.execute("INSERT INTO items VALUES (?, ?)", (item['title'], item['link'])) self.conn.commit() return item def close_spider(self, spider): self.conn.close()
在 settings.py
文件中启用该管道:
ITEM_PIPELINES = { 'myproject.pipelines.SqlitePipeline': 300, }
Scrapy 使用 HTTP 请求来抓取数据。可以通过 requests
参数在 Scrapy 爬虫中发起 HTTP 请求。以下是一个示例:
发起 GET 请求
import scrapy class ExampleSpider(scrapy.Spider): name = 'example' allowed_domains = ['example.com'] start_urls = ['http://example.com/'] def parse(self, response): # 发起 GET 请求 yield scrapy.Request('http://example.com/page', callback=self.parse_page) # 发起 POST 请求 yield scrapy.Request('http://example.com/post', method='POST', body='data=123', callback=self.parse_post) def parse_page(self, response): # 处理 GET 请求响应 pass def parse_post(self, response): # 处理 POST 请求响应 pass
parse
方法中,可以使用 yield
关键字发起新的请求,并指定回调函数。回调函数会在新请求的响应返回时调用。Scrapy 支持自定义请求头和参数。以下是设置请求头和参数的示例:
设置请求头
headers = { 'User-Agent': 'Mozilla/5.0', 'Content-Type': 'application/json', } yield scrapy.Request(url, headers=headers, callback=self.parse)
设置请求参数
data = { 'param1': 'value1', 'param2': 'value2', } yield scrapy.Request(url, method='POST', body=data, callback=self.parse)
FormRequest
类:
yield scrapy.FormRequest(url, formdata={'username': 'user', 'password': 'pass'}, callback=self.parse_login)
假设我们需要从 example.com
发起一个 GET 请求并抓取数据,可以在 news_scraper/spiders
目录下创建一个名为 http_request_spider.py
的文件:
import scrapy class HttpRequestSpider(scrapy.Spider): name = 'http_request' allowed_domains = ['example.com'] start_urls = ['http://example.com/'] def parse(self, response): # 发起 GET 请求 yield scrapy.Request('http://example.com/page', callback=self.parse_page) def parse_page(self, response): # 处理 GET 请求响应 pass
在 settings.py
文件中设置延迟时间:
DOWNLOAD_DELAY = 1
运行爬虫:
scrapy crawl http_request
下面是一个完整的 Scrapy 实战案例,用于从一个网站抓取新闻标题和链接。
scrapy startproject news_scraper
在 news_scraper/spiders
目录下创建一个名为 news_spider.py
的文件,并定义爬虫:
import scrapy class NewsSpider(scrapy.Spider): name = 'news' allowed_domains = ['example.com'] start_urls = ['http://example.com/news'] def parse(self, response): for article in response.css('div.article'): title = article.css('h2.title::text').get() link = article.css('a::attr(href)').get() yield { 'title': title, 'link': link, } next_page = response.css('a.next::attr(href)').get() if next_page is not None: yield response.follow(next_page, self.parse)
在命令行中执行以下命令运行爬虫:
scrapy crawl news
在 news_scraper/pipelines.py
中定义一个管道:
import json class NewsScraperPipeline(object): def __init__(self): self.file = open("items.json", "w") def process_item(self, item, spider): line = json.dumps(dict(item)) + "\n" self.file.write(line) return item def close_spider(self, spider): self.file.close()
在 settings.py
中启用管道:
ITEM_PIPELINES = { 'news_scraper.pipelines.NewsScraperPipeline': 300, }
在使用 Scrapy 进行网络爬取时,可能会遇到一些常见的问题。以下是一些常见问题的解答和调试方法:
解答:可以设置 DOWNLOAD_DELAY
参数来减缓抓取速度,避免被服务器封锁:
DOWNLOAD_DELAY = 1 # 1 秒延迟
解答:可以在 settings.py
中设置 REDIRECT_ENABLED
参数为 False
,并使用 response.meta['redirect_urls']
获取重定向 URL。
REDIRECT_ENABLED = False
解答:检查请求头是否正确设置,确保 User-Agent
和 Cookies
都正确。
headers = { 'User-Agent': 'Mozilla/5.0', 'Cookies': 'session=123456', }
解答:使用 Scrapy Shell 来验证选择器是否正确:
scrapy shell 'http://example.com'
然后在 Shell 中测试选择器:
response.css('div.article').getall()
解答:检查数据项是否符合预期格式,并确保管道正确处理数据。例如,使用 json
库将数据保存为 JSON 格式。
使用 Scrapy Shell
Scrapy Shell 是一个强大的调试工具,可以在不运行完整爬虫的情况下测试选择器和请求:
scrapy shell 'http://example.com'
打印日志
使用 logging
模块或 print
语句打印调试信息:
import logging logging.warning('This is a warning message')
设置日志级别
在 settings.py
中设置日志级别,以便获取更多调试信息:
LOG_LEVEL = 'DEBUG'
pdb
模块:
import pdb; pdb.set_trace()
通过这些调试技巧,您可以有效地查找并解决 Scrapy 爬虫中的问题。