Scrapy是一款强大的Python框架,用于抓取网站内容并结构化存储。它支持异步网络请求和多种数据解析方式,如XPath和CSS选择器。本文将详细介绍Scrapy的安装、配置及项目结构,并提供scrapy教程中的关键知识点和实战案例。
Scrapy 是一个用于抓取网站并提取结构化数据的 Python 框架。它被设计用于快速抓取数据并遵循网站的链接结构,支持异步网络请求,能够处理大规模的数据抓取任务。Scrapy 提供了丰富的功能,包括内置的中间件支持、强大的XPath和CSS选择器、内置的Spider和Item管道等。Scrapy 的架构设计使得它可以轻松地扩展和维护,非常适合用于构建复杂的网络爬虫项目。同时,Scrapy 还提供了强大的错误处理机制和自动防止被网站屏蔽的能力,使得开发者可以专注于数据抓取的逻辑设计。
Scrapy 是一个用于抓取网站并提取结构化数据的 Python 框架。它被设计用于快速抓取数据并遵循网站的链接结构,支持异步网络请求,能够处理大规模的数据抓取任务。Scrapy 提供了丰富的功能,包括内置的中间件支持、强大的XPath和CSS选择器、内置的Spider和Item管道等。Scrapy 的架构设计使得它可以轻松地扩展和维护,非常适合用于构建复杂的网络爬虫项目。同时,Scrapy 还提供了强大的错误处理机制和自动防止被网站屏蔽的能力,使得开发者可以专注于数据抓取的逻辑设计。
Scrapy 通常通过 Python 的包管理工具 pip
来安装。首先确保已安装 Python 3.6(或更高版本)和 pip。在安装 Python 时,一般会附带安装 pip,但如果没有安装,则可以通过运行 python -m ensurepip
安装。
安装 Scrapy 可以直接执行以下命令:
pip install scrapy
为了更好地管理 Python 项目,建议使用 virtualenv
创建一个虚拟环境来安装 Scrapy。创建虚拟环境的命令如下:
virtualenv my_project
然后激活虚拟环境:
source my_project/bin/activate
在虚拟环境下安装 Scrapy:
pip install scrapy
安装完 Scrapy 后,需要配置 Scrapy 环境。Scrapy 配置主要涉及 Scrapy 的设置文件 settings.py
,它位于 Scrapy 项目的根目录中。配置文件 settings.py
可以设置各种 Scrapy 选项,如下载延迟、日志级别、代理和用户代理等。
一个典型的 settings.py
文件内容如下:
# settings.py BOT_NAME = 'my_spider' SPIDER_MODULES = ['my_spider.spiders'] NEWSPIDER_MODULE = 'my_spider.spiders' DOWNLOAD_DELAY = 1 # 下载延迟 LOG_LEVEL = 'INFO' # 日志级别 ITEM_PIPELINES = { 'my_spider.pipelines.MyPipeline': 300, # 自定义管道 }
在 settings.py
中还可以设置代理和用户代理:
# 设置代理 HTTP_PROXY = 'http://proxy.example.com:8080' DOWNLOADER_MIDDLEWARES = { 'scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware': 1, } # 设置用户代理 USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3'
创建 Scrapy 项目是开始抓取数据的第一步。Scrapy 提供了命令行工具来帮助创建和管理项目。
创建 Scrapy 项目使用 scrapy startproject
命令。命令格式如下:
scrapy startproject my_project
这将创建一个名为 my_project
的 Scrapy 项目,项目结构如下:
my_project/ scrapy.cfg my_project/ __init__.py items.py middlewares.py pipelines.py settings.py spiders/ __init__.py
Scrapy 项目的结构如下:
scrapy.cfg
:项目配置文件,用于配置 Scrapy 的运行环境。my_project/
:项目的主目录。
__init__.py
:空文件,用于标识这个目录是一个 Python 包。items.py
:定义数据模型的文件。middlewares.py
:定义中间件的文件。pipelines.py
:定义数据处理管道的文件。settings.py
:项目的全局配置文件。spiders/
:存放爬虫脚本的目录。__init__.py
:空文件,用于标识这个目录是一个 Python 包。items.py
文件定义了爬取数据的结构。一个典型的 items.py
文件如下:
# items.py import scrapy class MyItem(scrapy.Item): name = scrapy.Field() description = scrapy.Field()
middlewares.py
文件定义了各种中间件,用于处理请求和响应,例如代理中间件、用户代理中间件等。一个简单的中间件示例如下:
# middlewares.py from scrapy import signals class MyMiddleware(object): @classmethod def from_crawler(cls, crawler): s = cls() crawler.signals.connect(s.spider_opened, signal=signals.spider_opened) return s def process_request(self, request, spider): # 拦截请求 return None def spider_opened(self, spider): spider.logger.info('Spider opened: %s' % spider.name)
pipelines.py
文件定义了数据处理管道,用于处理 Item 对象,例如清洗数据、持久化数据等。一个简单的管道示例如下:
# pipelines.py class MyPipeline(object): def process_item(self, item, spider): # 清洗数据 return item
settings.py
文件是项目的全局配置文件,可以设置各种 Scrapy 的选项,例如下载延迟、日志级别等。一个典型的 settings.py
文件如下:
# settings.py BOT_NAME = 'my_project' SPIDER_MODULES = ['my_project.spiders'] NEWSPIDER_MODULE = 'my_project.spiders' DOWNLOAD_DELAY = 1 LOG_LEVEL = 'INFO' ITEM_PIPELINES = { 'my_project.pipelines.MyPipeline': 300, }
spiders/
目录存放所有爬虫脚本,每个脚本都继承自 scrapy.Spider
类。一个简单的爬虫示例如下:
# spiders/my_spider.py import scrapy class MySpider(scrapy.Spider): name = 'my_spider' start_urls = ['http://example.com'] def parse(self, response): # 解析页面 pass
编写 Scrapy 爬虫是数据抓取的核心任务。Scrapy 提供了强大的功能来帮助我们编写高效的爬虫。
Scrapy 爬虫是用于自动抓取网页数据的程序。一个 Scrapy 爬虫通常包含以下几个部分:
编写一个简单的 Scrapy 爬虫,抓取网站的标题和链接。
在 spiders/
目录下创建一个新的 Python 文件,例如 example_spider.py
:
# spiders/example_spider.py import scrapy class ExampleSpider(scrapy.Spider): name = 'example' start_urls = ['http://example.com'] def parse(self, response): for title in response.css('h1::text').getall(): yield {'title': title} for url in response.css('a::attr(href)').getall(): yield response.follow(url, self.parse)
parse
函数是 Scrapy 爬虫的默认解析函数。response.css('h1::text').getall()
用于提取所有 <h1>
标签中的文本。response.css('a::attr(href)').getall()
用于提取所有 <a>
标签的 href
属性。response.follow(url, self.parse)
用于跟踪链接并继续抓取。运行爬虫使用 scrapy crawl
命令:
scrapy crawl example
这将启动名为 example
的爬虫并开始抓取数据。
Scrapy 提供了多种高级特性来增强数据抓取的灵活性和效率。本节介绍 XPath 和 CSS 选择器,以及中间件和管道的使用。
XPath 和 CSS 选择器是 Scrapy 中常用的解析工具,用于提取 HTML 文档中的内容。
XPath 是一种在 XML 文档中查找信息的强大语言,Scrapy 中可以使用 XPath 来提取 HTML 中的内容。例如,提取所有 <p>
标签中的文本:
# 使用XPath提取<p>标签中的文本 for paragraph in response.xpath('//p/text()').getall(): print(paragraph)
CSS 选择器是另一种常用的解析工具,语法简单且易于阅读。例如,提取所有 <a>
标签的 href
属性:
# 使用CSS选择器提取所有<a>标签的href属性 for link in response.css('a::attr(href)').getall(): print(link)
演示如何使用 XPath 和 CSS 选择器提取网页内容。假设要抓取一个简单的 HTML 页面:
<!DOCTYPE html> <html> <head><title>Example Page</title></head> <body> <h1>Page Title</h1> <p>Paragraph 1</p> <ul> <li><a href="/link1">Link 1</a></li> <li><a href="/link2">Link 2</a></li> </ul> </body> </html>
使用 XPath 提取 <h1>
标签的文本:
titles = response.xpath('//h1/text()').getall() print(titles)
使用 CSS 选择器提取 <a>
标签的 href
属性:
links = response.css('a::attr(href)').getall() print(links)
Scrapy 中的中间件和管道可以增强数据抓取的灵活性和处理能力。
中间件包括请求中间件和响应中间件,用于处理请求和响应。
请求中间件用于修改请求和响应,例如添加代理或处理重定向。
# middlewares.py from scrapy import signals class ExampleMiddleware(object): @classmethod def from_crawler(cls, crawler): s = cls() crawler.signals.connect(s.spider_opened, signal=signals.spider_opened) return s def process_request(self, request, spider): request.meta['proxy'] = 'http://example.com:8080' return request def process_response(self, request, response, spider): return response def spider_opened(self, spider): spider.logger.info('Spider opened: %s' % spider.name)
响应中间件用于处理响应,例如解析响应内容或处理重定向。
class AnotherMiddleware(object): def process_response(self, request, response, spider): response = response.replace(body=response.body.replace(b'old', b'new')) return response
管道用于处理数据,例如清洗数据或持久化数据。
定义一个简单的管道,用于清洗数据:
# pipelines.py class ExamplePipeline(object): def process_item(self, item, spider): item['title'] = item['title'].strip() return item
在 settings.py
中注册管道:
# settings.py ITEM_PIPELINES = { 'my_project.pipelines.ExamplePipeline': 300, }
演示如何使用中间件和管道处理数据。假设要抓取一个简单的 HTML 页面:
<!DOCTYPE html> <html> <head><title>Example Page</title></head> <body> <h1>Page Title</h1> <p>Paragraph 1</p> <ul> <li><a href="/link1">Link 1</a></li> <li><a href="/link2">Link 2</a></li> </ul> </body> </html>
使用中间件修改请求和响应:
# middlewares.py class ExampleMiddleware(object): def process_request(self, request, spider): request.meta['proxy'] = 'http://example.com:8080' return request def process_response(self, request, response, spider): response = response.replace(body=response.body.replace(b'old', b'new')) return response
注册中间件:
# settings.py DOWNLOADER_MIDDLEWARES = { 'my_project.middlewares.ExampleMiddleware': 543, }
使用管道清洗数据:
# pipelines.py class ExamplePipeline(object): def process_item(self, item, spider): item['title'] = item['title'].strip() return item
注册管道:
# settings.py ITEM_PIPELINES = { 'my_project.pipelines.ExamplePipeline': 300, }
Scrapy 的实战演练包括简单的网页数据抓取和动态网页数据抓取。
一个简单的网页数据抓取案例用于演示如何抓取网站的内容。假设要抓取一个简单的 HTML 页面:
<!DOCTYPE html> <html> <head><title>Example Page</title></head> <body> <h1>Page Title</h1> <p>Paragraph 1</p> <ul> <li><a href="/link1">Link 1</a></li> <li><a href="/link2">Link 2</a></li> </ul> </body> </html>
创建一个新的爬虫文件 simple_spider.py
:
# spiders/simple_spider.py import scrapy class SimpleSpider(scrapy.Spider): name = 'simple' start_urls = ['http://example.com'] def parse(self, response): # 提取标题 title = response.css('h1::text').get() print(f'Title: {title}') # 提取段落 paragraphs = response.css('p::text').getall() for p in paragraphs: print(f'Paragraph: {p}') # 跟踪链接 for url in response.css('a::attr(href)').getall(): yield response.follow(url, self.parse)
运行爬虫使用 scrapy crawl
命令:
scrapy crawl simple
这将抓取 http://example.com
页面的标题、段落和链接,并跟踪链接继续抓取。
动态网页数据抓取涉及到抓取 JavaScript 渲染的页面内容,通常使用 Selenium 或其他工具加载 JavaScript。
创建一个新的爬虫文件 dynamic_spider.py
:
# spiders/dynamic_spider.py import scrapy from selenium import webdriver from scrapy.selector import Selector class DynamicSpider(scrapy.Spider): name = 'dynamic' start_urls = ['http://example.com'] def __init__(self): self.driver = webdriver.Chrome() def parse(self, response): self.driver.get(response.url).get() sel = Selector(text=self.driver.page_source) # 提取数据 for item in sel.css('div.item'): yield { 'title': item.css('h2::text').get(), 'link': item.css('a::attr(href)').get(), 'desc': item.css('p::text').get(), } self.driver.quit()
运行爬虫使用 scrapy crawl
命令:
scrapy crawl dynamic
这将使用 Selenium 加载 JavaScript 并抓取页面内容。
在使用 Scrapy 进行数据抓取时,可能会遇到一些常见问题,同时也可以通过一些技巧进行性能优化。
User-Agent
,模拟不同的浏览器访问。settings.py
中设置 DOWNLOAD_DELAY
,减缓访问速度。robots.txt
规则,避免过度抓取。解析规则的效率直接影响抓取性能。优化解析规则可以通过减少解析步骤、减少不必要的循环等方法。
# 不优化的解析规则 for item in response.css('div.item'): title = item.css('h2::text').get() link = item.css('a::attr(href)').get() desc = item.css('p::text').get() yield { 'title': title, 'link': link, 'desc': desc, } # 优化后的解析规则 items = response.css('div.item') for item in items: yield { 'title': item.css('h2::text').get(), 'link': item.css('a::attr(href)').get(), 'desc': item.css('p::text').get(), }
Scrapy 使用异步网络请求,可以显著提高抓取效率。确保代码中尽量避免阻塞操作。
在中间件中进行缓存、代理处理等操作可以减轻服务器压力。
# 使用缓存中间件 class CacheMiddleware(object): cache = {} def process_request(self, request, spider): if request.url in self.cache: return self.cache[request.url] else: response = self.fetch(request) self.cache[request.url] = response return response def fetch(self, request): # 实际抓取请求 return scrapy.http.HtmlResponse(url=request.url)
假设要抓取一个简单的 HTML 页面:
<!DOCTYPE html> <html> <head><title>Example Page</title></head> <body> <h1>Page Title</h1> <p>Paragraph 1</p> <ul> <li><a href="/link1">Link 1</a></li> <li><a href="/link2">Link 2</a></li> </ul> </body> </html>
优化解析规则:
# 优化后的解析规则 items = response.css('div.item') for item in items: yield { 'title': item.css('h2::text').get(), 'link': item.css('a::attr(href)').get(), 'desc': item.css('p::text').get(), }
使用缓存中间件:
# 缓存中间件 class CacheMiddleware(object): cache = {} def process_request(self, request, spider): if request.url in self.cache: return self.cache[request.url] else: response = self.fetch(request) self.cache[request.url] = response return response def fetch(self, request): # 实际抓取请求 return scrapy.http.HtmlResponse(url=request.url)
注册缓存中间件:
# settings.py DOWNLOADER_MIDDLEWARES = { 'my_project.middlewares.CacheMiddleware': 543, } `` 通过以上优化,可以显著提高 Scrapy 的抓取效率和稳定性。