Scrapy 是一个为了爬取网站数据、提取结构性数据而编写的开源 Python 应用框架。它基于 Twisted 异步网络框架开发,能够同时处理多个请求,被广泛用于数据挖掘、监测和自动化测试等领域。
1
安装与项目结构
安装
pip install scrapy
创建项目
终端输入:scrapy startproject scrapy_project
题外话:看见这个指令我瞬间就觉得眼熟,好像python里面还有一个项目创建命令几乎如出一辙。django-admin startproject myproject,发现没有就是它,python web的框架。它俩有什么共同点呢?
结论是,Django 和 Scrapy 对项目目录结构都有强制要求,比如 Scrapy 必须有 spiders 文件夹,Django 必须有 settings.py。 它们必须提供 startproject 命令,否则用户根本无法手动搭建出正确的运行环境。startproject 是“重量级/全功能”框架的标配特征,代表了一种“约定优于配置”的设计理念。
3. 项目目录结构

文件 | 说明 |
spiders | 存放爬虫代码的目录 |
items.py | 定义要抓取的数据结构 |
middlewares.py | 中间件(代理、UA池等) |
pipelines.py | 数据管道,处理抓取的数据(清洗、存储等) |
settings.py | 全局配置文件 |
scrapy.cfg | 部署配置文件 |
2
实战演练
爬取网站:http://quotes.toscrape.com/

定义数据结构
在 items.py 中定义要抓取的字段
import scrapyclass QuoteItem(scrapy.Item):# define the fields for your item here like:# name = scrapy.Field()text = scrapy.Field() # 内容author = scrapy.Field() # 作者tags = scrapy.Field() # 标签
2. 编写爬虫文件
在 spiders 目录下创建 quotes_spider.py
可以自己创建,也可以指令创建:
cd scrapy_project #先进入项目目录# scrapy genspider 文件名 url(网站域名)scrapy genspider quotes_spider http://quotes.toscrape.com/
建议用指令创建,因为它会给你搭出大致框架,我们只需要完善逻辑。
import scrapyfrom scrapy_project.items import QuoteItemclass QuotesSpiderSpider(scrapy.Spider):name = "quotes_spider" # 爬虫文件名allowed_domains = ["quotes.toscrape.com"] # 网站域名start_urls = ["http://quotes.toscrape.com"] # 第一个要抓取的urloffset = 1def parse(self, response):# 解析页面for i in response.xpath('//div[@class="col-md-8"]/div'):quote = QuoteItem()quote['text'] = i.xpath('.//span[@class="text"]/text()').get()quote['author'] = i.xpath('.//small[@class="author"]/text()').get()# tags 通常有多个,所以用 .getall() 提取所有匹配到的文本,返回一个字符串列表quote['tags'] = i.xpath('.//a[@class="tag"]/text()').getall()yield quote # 将数据提交给 Pipeline# 提取下一页链接,实现自动翻页# 方案一:if self.offset <= 10:self.offset += 1url = f"http://quotes.toscrape.com/page/{self.offset}/"yield scrapy.Request(url=url, callback=self.parse)# 方案二:# next_page = response.xpath('//li[@class="next"]/a/@href').get()# if next_page is not None:# yield response.follow(next_page,callback=self.parse)
有两个易错点,即新手最容易踩坑的概念:“XPath 的上下文”和“选择器的返回值类型”。
(1)循环里面的 i.xpath(...) 写法里不要少了至关重要的点:.(点号)。
i.xpath('//span...'):开头的 // 代表从整个文档的根节点开始找。这意味着,不管循环到第几次,它都会去整个网页里把所有的名言 span 都抓回来塞给这一个 item。
i.xpath('.//span...'):开头的 . 代表从当前节点 i 内部开始找。这才是我们要的“在当前这条名言里找作者、找正文”。
(2)如果你的item返回的是“列表”和“Selector对象”,那就要注意看,你是不是忘了加get()。
Scrapy 的 .xpath() 方法总是返回一个列表(类似数组的 SelectorList 对象)。哪怕页面上只有一个匹配结果,它也放在列表里返回给你。
解决办法: 你需要用 .get() 或 .getall() 方法把数据从 Selector 对象里“提取”出来变成字符串。
(3)总结
在 Scrapy 解析数据时,记住这三步:
定范围:for i in ... 循环拿到了每一个条目的节点(这就是范围)。
找子元素:在循环内部写 XPath 时,一定要以 . 开头(如 .//div),否则就会跳出范围,搜全页。
提数据:
如果只要一个数据(如标题、作者):用 .xpath(...).get()。
如果要一组数据(如标签,如下图所示):用 .xpath(...).getall(),

3. 编写管道
在 pipelines.py 中处理数据(数据清洗、存入数据库等),需要利用 Scrapy 提供的三个特殊方法:open_spider、close_spider 和 process_item。
from itemadapter import ItemAdapterimport pymysqlfrom scrapy_project.settings import *class ScrapyProjectPipeline:# 在这里进行数据清洗def process_item(self, item, spider):item['text'] = item['text'].strip("“”")return item # 必须返回 item,给后续的 pipeline 使用class MysqlPipeline:# 1. 爬虫开始时:连接数据库def open_spider(self, spider):self.conn = pymysql.connect(host=MYSQL_HOST,port=MYSQL_PORT,user=MYSQL_USER,password=MYSQL_PASSWORD,database=MYSQL_DATABASE,)self.cursor = self.conn.cursor()spider.logger.info("数据库连接成功!")# 2. 爬虫结束时:关闭连接def close_spider(self, spider):self.cursor.close()self.conn.close()spider.logger.info("数据库连接关闭!")# 3. 处理每一条 Item:执行 SQL 插入def process_item(self, item, spider):try:# 别忘了提前在数据库里建表:# CREATE TABLE quotes_table (# id INT AUTO_INCREMENT PRIMARY KEY,# text VARCHAR(500),# author VARCHAR(50),# tags VARCHAR(255)# );sql = "INSERT INTO quotes_table (text,author,tags) VALUES (%s,%s,%s)"# 处理数据:tags 如果是列表,用 join 转成字符串tags_str = ",".join(item['tags']) ifisinstance(item['tags'], list) else item['tags']self.cursor.execute(sql, (item['text'], item['author'], tags_str))self.conn.commit()spider.logger.info("成功插入数据!")except Exception as e:self.conn.rollback()spider.logger.error(f"数据库插入失败: {e}")return item # 必须返回 item,给后续的 pipeline 使
配置设置
在 settings.py 中开启 Pipeline 并设置 User-Agent:
# 1.设置 User-Agent,伪装成浏览器USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:2.0.1) Gecko/20100101 Firefox/4.0.1"# 2.开启 Pipeline,数字越小优先级越高ITEM_PIPELINES = {"scrapy_project.pipelines.ScrapyProjectPipeline": 300, # 负责清洗"scrapy_project.pipelines.MysqlPipeline":400# 负责存储 (数字越大,优先级越低,越后执行)}# 3.配置数据库连接参数MYSQL_HOST = "127.0.0.1"MYSQL_PORT = 3306MYSQL_USER = "root"MYSQL_PASSWORD = "123456"MYSQL_DATABASE = "my_db"
5. 运行爬虫
在项目根目录(scrapy.cfg 所在目录)下运行:
scrapy crawl quotes_spider
就可以得到以下结果:

3
选择器
Scrapy 支持两种选择器:
XPath Selector: response.xpath('//div[@class="col-md-8"]/div'),支持根据文本内容查找节点,适合复杂的结构提取。
CSS Selector: response.css('div.col-md-8 div'),适合前端熟悉的开发者。比如上面示例换成css选择器如下:
for i in response.css('div.col-md-8 > div'): # 或者简写为 'div.col-md-8 div'quote = QuoteItem()# 1. 提取 text# XPath: .//span[@class="text"]/text()# CSS: span.text 提取标签,::text 提取文本,.get() 取第一个quote['text'] = i.css('span.text::text').get()# 2. 提取 author# XPath: .//small[@class="author"]/text()# CSS: small.author 提取标签,::text 提取文本quote['author'] = i.css('small.author::text').get()# 3. 提取 tags# XPath: .//a[@class="tag"]/text()# CSS: a.tag 提取标签,::text 提取文本,.getall() 取全部quote['tags'] = i.css('a.tag::text').getall()yield quote
核心语法对比:
功能 | XPath 写法 | CSS 写法 | 说明 |
按 Class 查找 | div[@class="quote"] | div.quote | CSS 用 . 代表 class |
按 ID 查找 | div[@id="main"] | div#main | CSS 用 # 代表 id |
提取文本 | /text() | ::text | CSS 用伪元素 ::text |
提取属性 | /@href | ::attr(href) | CSS 用 ::attr(属性名) |
提取第一个 | xpath(…).get() | css(…).get() | 结果相同 |
提取全部 | xpath(…).getall() | css(…).getall() | 结果相同 |
长按或扫描下方二维码,免费获取 Python公开课和大佬打包整理的几百G的学习资料,内容包含但不限于Python电子书、教程、项目接单、源码等等
▲扫描二维码-免费领取
推荐阅读
点击 阅读原文了解更多