本文详细介绍了如何从零开始搭建Scrapy环境并编写简单的爬虫项目,涵盖了Scrapy的基本架构、组件配置以及实战演练。通过具体示例代码,新手可以快速上手掌握Scrapy项目实战。
Scrapy简介与环境搭建Scrapy 是一个高度模块化的开源爬虫框架,用于从网站上抓取数据。它被广泛应用于数据提取、网络爬虫、网页自动化等场景。Scrapy设计之初就考虑到了可维护性和扩展性,通过不同的组件如Spider、Item、Pipeline等实现不同的功能,使得开发者能够专注于业务逻辑的实现而无需过多关注底层实现。
Scrapy采用异步模型来处理网络请求,其主要组件包括:
为了搭建Scrapy开发环境,首先需要安装Python。以下是安装步骤:
pip install scrapy
virtualenv
或venv
,以避免项目间环境冲突。
pip install virtualenv
virtualenv my_env source my_env/bin/activate # 在Windows上,使用 `my_env\Scripts\activate`
通过Scrapy shell快速上手,以一个简单的新闻网站爬虫为例。
scrapy startproject my_first_project
cd my_first_project scrapy genspider my_first_spider example.com
编辑生成的Spider文件,定义基础抓取逻辑。
import scrapy class MyFirstSpider(scrapy.Spider): name = 'my_first_spider' allowed_domains = ['example.com'] start_urls = [ 'http://example.com' ] def parse(self, response): for title in response.css('title'): yield {'title_text': title.get()}
scrapy crawl my_first_spider
通过以上步骤,用户可以快速创建并运行一个简单的Scrapy爬虫。
Scrapy的基本组件与配置Scrapy项目的标准目录结构:
my_first_project/ ├── my_first_project/ │ ├── __init__.py │ ├── items.py │ ├── middlewares.py │ ├── pipelines.py │ ├── settings.py │ └── spiders/ │ └── my_first_spider.py ├── scrapy.cfg └── requirements.txt
示例代码:
import scrapy class MyAnotherSpider(scrapy.Spider): name = 'my_another_spider' allowed_domains = ['example.org'] start_urls = ['http://example.org'] def parse(self, response): for item in response.css('div.item'): yield { 'title': item.css('h2 a::text').get(), 'link': item.css('h2 a::attr(href)').get(), 'desc': item.css('p::text').get() }
class MyItem(scrapy.Item): title = scrapy.Field() link = scrapy.Field() desc = scrapy.Field()
class MyPipeline(object): def process_item(self, item, spider): if not item['title']: raise DropItem("Missing title in %s" % item) return item
Scrapy的配置可以通过settings.py
文件来控制。例如,开启或关闭日志记录,设置下载延迟等。
FEED_FORMAT = 'jsonlines' FEED_URI = 'results.jsonl' LOG_LEVEL = 'WARNING' DOWNLOAD_DELAY = 0.5
编写一个简单的爬虫,从一个网页上提取所有链接和标题。
示例代码:
import scrapy class SimpleSpider(scrapy.Spider): name = 'simple_spider' allowed_domains = ['example.net'] start_urls = ['http://example.net'] def parse(self, response): for link in response.css('a'): yield { 'href': link.attrib['href'], 'text': link.attrib['text'] }
XPath 和 CSS 选择器是Scrapy中两种常用的语法,用于从HTML中提取数据。
response.xpath('//div[@class="item"]/h2/a/text()').get()
response.css('div.item h2 a::text').get()
处理爬虫过程中出现的异常。
示例代码:
import scrapy class ExceptionSpider(scrapy.Spider): name = 'exception_spider' allowed_domains = ['example.com'] start_urls = ['http://example.com'] def parse(self, response): try: yield { 'data': response.css('div.missing').get() } except Exception as e: print(f'出现异常:{e}') pass
Scrapy支持多种数据存储方式,如CSV、JSON、数据库等。
FEED_FORMAT = 'json' FEED_URI = 'output.json'
使用Pipeline对爬取的数据进行清洗和格式化。
class MyCustomPipeline(object): def process_item(self, item, spider): item['title'] = item['title'].strip() return item
清洗数据,去除不必要的字符或格式化数据。
示例代码:
def clean_data(self, text): return text.replace('\n', '').strip() class MySpider(scrapy.Spider): def parse(self, response): cleaned_text = self.clean_data(response.css('body::text').get()) yield {'cleaned_text': cleaned_text}
模拟登录和设置请求头信息。
示例代码:
import scrapy class LoginSpider(scrapy.Spider): name = 'login_spider' allowed_domains = ['example.com'] def start_requests(self): return [scrapy.FormRequest('http://example.com/login', formdata={'username': 'test', 'password': 'test'}, callback=self.logged_in)] def logged_in(self, response): if 'Login failed' in response.text: self.log("Login failed") else: yield scrapy.Request('http://example.com/protected', callback=self.parse_page) def parse_page(self, response): for item in response.css('div.item'): yield { 'title': item.css('h2 a::text').get(), 'link': item.css('h2 a::attr(href)').get(), 'desc': item.css('p::text').get() }
中间件允许在请求和响应之间插入额外的处理逻辑。
class MyCustomMiddleware(object): def process_request(self, request, spider): if not request.meta.get('proxy'): request.meta['proxy'] = 'http://proxy.example.com' return request
对于动态网页,使用scrapy-playwright
等库来渲染JavaScript。
示例代码:
pip install scrapy-playwright
import scrapy from scrapy_playwright.page import PageMethod class DynamicSpider(scrapy.Spider): name = 'dynamic_spider' allowed_domains = ['example.com'] start_urls = ['http://example.com'] def start_requests(self): yield scrapy.Request('http://example.com', callback=self.parse, meta=dict( playwright=True, playwright_page_methods=[ PageMethod('wait_for_selector', 'div.item') ] )) def parse(self, response): for item in response.css('div.item'): yield { 'title': item.css('h2 a::text').get(), 'link': item.css('h2 a::attr(href)').get(), 'desc': item.css('p::text').get() }
根据具体的项目需求,选择合适的爬虫组件和策略。比如抓取特定的新闻网站,可以编写一个Spider来抓取新闻标题、链接和发布时间。
示例代码:
# items.py import scrapy class NewsItem(scrapy.Item): title = scrapy.Field() link = scrapy.Field() pub_date = scrapy.Field() # spiders/example_spider.py import scrapy from my_project.items import NewsItem class ExampleSpider(scrapy.Spider): name = 'example_spider' allowed_domains = ['example.com'] start_urls = ['http://example.com'] def parse(self, response): for news in response.css('div.post'): item = NewsItem() item['title'] = news.css('h2 a::text').get() item['link'] = news.css('h2 a::attr(href)').get() item['pub_date'] = news.css('.pub_date::text').get() yield item
搭建一个完整的Scrapy项目,包括定义Spider、处理数据格式和存储。
示例代码:
# items.py import scrapy class NewsItem(scrapy.Item): title = scrapy.Field() link = scrapy.Field() pub_date = scrapy.Field() # spiders/example_spider.py import scrapy from my_project.items import NewsItem class ExampleSpider(scrapy.Spider): name = 'example_spider' allowed_domains = ['example.com'] start_urls = ['http://example.com'] def parse(self, response): for news in response.css('div.post'): item = NewsItem() item['title'] = news.css('h2 a::text').get() item['link'] = news.css('h2 a::attr(href)').get() item['pub_date'] = news.css('.pub_date::text').get() yield item
持续优化和维护爬虫,确保其能够高效且稳定地运行。这包括定期更新Spider代码以适应网站结构的变化,优化数据存储策略,以及监控爬虫性能并及时调整配置。
LOG_LEVEL
来控制日志输出级别。scrapy stats
命令获取爬虫运行统计信息。DOWNLOAD_DELAY
来避免请求过于频繁。CONCURRENT_REQUESTS_PER_DOMAIN
和CONCURRENT_REQUESTS_PER_IP
控制并发数量。User-Agent
和Accept-Language
,以模拟真实浏览器的行为。# settings.py DOWNLOAD_DELAY = 0.5 CONCURRENT_REQUESTS_PER_DOMAIN = 16 CONCURRENT_REQUESTS_PER_IP = 16 USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36' ACCEPT_LANGUAGE = 'en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7'
通过以上步骤和示例代码,新手可以快速从Scrapy的入门到上手,并掌握基本和进阶的功能。希望这些内容能帮助你构建强大的网络爬虫,高效地抓取需要的数据!