Python学习第二十六天
前面说了最基础的使用、数据的爬取后会使用选择器进行解析数据、然后将数据按照项目(即转为对象类型)的类型,接着创建项目后就可以使用管道来对项目进行进一步处理(比如存数据库啥的),中间件的话其实就是用于全局处理请求和响应。
选择器
官网:从html中获取数据,使用xpath,也可使用beautiful soup。
使用
# 链接打开本地的html于shell 命令行 不知道怎么使用命令 scrapy --help shell 和那个直接写到py中是一样的方法是一样的
scrapy shell ./test.html
# 首先获取title get获取单个 getall()获取全部
response.css("title::text").get()
# 另一种方式
response.xpath("//title/text()").get()
# 获取图片中的src一般需要这个图片地址
response.css('img').xpath("@src").getall()
# 获取图片 attrib获取属性
response.css('img').attrib['src']
# 使用attr获取属性
response.css("img::attr('src')").getall()
# 或者直接使用xpath来获取
response.xpath("//div[@id='lg']/img/@src").getall()
方法
方法 | 说明 | 示例 |
---|---|---|
CSS 选择器方法 | ||
css() | 使用 CSS 选择器选择元素 | response.css('div.title') |
::text | 提取文本内容 | response.css('div.title::text') |
::attr(属性名) | 提取属性值 | response.css('a::attr(href)') |
XPath 选择器方法 | ||
xpath() | 使用 XPath 选择元素 | response.xpath('//div[@class="title"]') |
/text() | 提取文本内容 | response.xpath('//div/text()') |
/@属性名 | 提取属性值 | response.xpath('//a/@href') |
通用方法 | ||
get() | 提取第一个匹配结果(Scrapy 2.0+) | response.css('div.title::text').get() |
getall() | 提取所有匹配结果(Scrapy 2.0+) | response.css('div.title::text').getall() |
extract() | 提取第一个匹配结果(旧版) | response.css('div.title::text').extract() |
extract_first() | 提取第一个匹配结果(旧版) | response.css('div.title::text').extract_first() |
re() | 使用正则表达式提取 | response.css('div::text').re(r'\d+') |
re_first() | 使用正则表达式提取第一个匹配 | response.css('div::text').re_first(r'\d+') |
链式调用 | ||
方法链 | 可以连续调用选择方法 | response.css('div').xpath('.//a') |
其他方法 | ||
attrib | 获取属性字典 | response.css('a')[0].attrib |
join() | 拼接多个选择结果 | response.css('div::text').getall().join(' ') |
项目
官网:剪贴的主要目标是从非结构化源(通常是网页)中提取结构化数据。 Spiders 将提取的数据返回为 items ,定义键-值对的Python对象。
使用
# 第一使用命令创建项目 跟django类似
scrapy startproject testproject
# 第二使用命令创建test.py 我们要使用的是本地文件将创建出来的文件去掉allowed_domains 并将start_urls地址改为本地即可 将test.py移动到spiders下
scrapy genspider test test.com
# 执行运行命令
scrapy crawl test
其中item.py中内容为
import scrapy
# 主要是为了将 爬回来的数据封装成对象 方便后续使用
class TestprojectItem(scrapy.Item):
title = scrapy.Field()
url = scrapy.Field()
其中test.py中内容为
import scrapy
import os
from ..items import TestprojectItem
# 项目测试
class TestSpider(scrapy.Spider):
name = "test"
# 或者直接卸载头部的strt_url中 一样的 为什么知道这个方法 查看父类的spider 集成了 所以使用子类会自动覆盖父类相同方法
# 路劲注意 file:///是本地文件开头 如果是绝对路径自己直接写即可 如果是相对路径使用下面的即可
def start_requests(self):
# 获取当前目录的绝对路径
current_dir = os.path.dirname(os.path.abspath(__file__))
file_path = os.path.join(current_dir, 'test.html')
# 替换反斜杠为正斜杠,并添加 file:/// 前缀
file_url = 'file:///' + file_path.replace('\\', '/')
yield scrapy.Request(url=file_url, callback=self.parse)
def parse(self, response):
item = TestprojectItem()
item['url'] = response.css('img').attrib['src'].replace("//","")
item['title'] = response.xpath("//title/text()").get()
print("item.title:",item['title']) # item.title: 百度一下,你就知道
return item
方法和属性
类别 | 属性/方法 | 说明 | 示例 |
---|---|---|---|
Item 属性 | fields | 包含所有字段定义的字典(自动生成) | ```python |
class ProductItem(scrapy.Item): | |||
name = scrapy.Field() | |||
print(ProductItem.fields) # 输出: {'name': {}} | |||
``` | |||
Item 方法 | __init__() | 初始化Item(可覆盖以添加自定义逻辑) | ```python |
def init(self, *args, **kwargs): | |||
super().init(*args, **kwargs) | |||
self['timestamp'] = datetime.now() | |||
``` | |||
get() / set() | 获取或设置字段值 | ```python | |
item = ProductItem() | |||
item.set('name', 'Apple') # 设置 | |||
print(item.get('name')) # 获取: 'Apple' | |||
``` | |||
keys() | 返回所有字段名(列表) | print(item.keys())) # 输出: ['name', 'price'] | |
items() | 返回字段键值对(元组列表) | print(item.items())) # 输出: [('name', 'Apple'), ('price', None)] | |
__setitem__() / __getitem__() | 支持字典式访问(如 item['name'] = 'Apple' ) | ```python | |
item['price'] = 10.5 | |||
print(item['price']) # 输出: 10.5 | |||
``` | |||
覆盖方法 | to_dict() | 自定义Item转字典的逻辑(默认返回所有字段) | ```python |
def to_dict(self): | |||
data = super().to_dict() | |||
data['discounted'] = self['price'] * 0.9 | |||
return data | |||
``` | |||
validate() | 自定义字段验证逻辑(需手动调用) | ```python | |
def validate(self): | |||
if not self.get('name'): | |||
raise ValueError("Name field is required") |
管道
官网:管道用于处理爬取到的Item,执行数据清洗、验证、存储等操作。
用途
-
清理HTML数据
-
验证抓取的数据(检查项目是否包含某些字段)
-
检查重复项(并删除它们)
-
将爬取的项目存储在数据库中
使用
启用管道将settings.py中的ITEM_PIPELINES这个注释打开或者增加自己的管道内容
# 在此设置中分配给类的整数值决定了它们的运行顺序:项从低值类传递到高值类。习惯上把这些数字定义在0-1000范围内,相当于是运行顺序 官网概念哈
ITEM_PIPELINES = {
# 先执行校验 后面的值越小 越先走
"testproject.pipelines.pipelines.TestprojectPipeline": 200,
# 在入库
"testproject.pipelines.sqlite_pipelines.SQLitePipeline": 300,
}
import sqlite3
class SQLitePipeline:
def __init__(self, db_path):
self.db_path = db_path
@classmethod
def from_crawler(cls, crawler):
return cls(
db_path=crawler.settings.get('SQLITE_PATH', 'scrapy_data.db')
)
def open_spider(self, spider):
self.connection = sqlite3.connect(self.db_path)
# 获取游标
self.cursor = self.connection.cursor()
# 创建表
self.cursor.execute('''
CREATE TABLE IF NOT EXISTS test_table (
id INTEGER PRIMARY KEY AUTOINCREMENT,
url TEXT,
title TEXT
)
''')
self.connection.commit()
def close_spider(self, spider):
self.connection.close()
def process_item(self, item, spider):
print("--------SQLitePipeline我后走-------:")
self.cursor.execute(
"INSERT INTO test_table (url, title) VALUES (?, ?)",
(item['url'], item['title'])
)
self.connection.commit()
return item
方法
方法 | 必须实现 | 说明 | 参数 | 返回值 |
---|---|---|---|---|
| ✅ 是 | 核心方法,处理每个Item的主逻辑 | - | 必须返回 |
| ❌ 否 | Spider启动时调用(可选),用于初始化资源(如打开文件、连接数据库) |
| 无要求 |
| ❌ 否 | Spider关闭时调用(可选),用于清理资源(如关闭文件、断开数据库连接) |
| 无要求 |
| ❌ 否 | 类方法(可选),用于从Crawler获取配置(如访问Settings) |
| 返回Pipeline实例 |
中间件
官网:Spider中间件是一个钩子框架,可以钩住Scrapy的Spider处理机制,在该机制中,您可以插入自定义功能来处理发送到的响应。 蜘蛛 用于处理和处理由spider生成的请求和项目。
用途
-
设置User-Agent
-
代理IP处理
-
请求重试
-
响应修改
使用
将setting.py中的DOWNLOADER_MIDDLEWARES、SPIDER_MIDDLEWARES注释打开并添加自己的中间件
# 将这两个注释打开 后面的参数与管道的参数相同越小 优先级越高
SPIDER_MIDDLEWARES = {
"testproject.middlewares.TestprojectSpiderMiddleware": 543,
}
DOWNLOADER_MIDDLEWARES = {
"testproject.middlewares.TestprojectDownloaderMiddleware": 543,
}
# 清空下window下的命令行 要不然老是满
cls
# 运行命令
scrapy crawl test
可以将他下载到本地然后在进行解析目前代码没写只写了一个执行顺序后续项目完善
class TestprojectDownloaderMiddleware:
@classmethod
def from_crawler(cls, crawler):
s = cls()
crawler.signals.connect(s.spider_opened, signal=signals.spider_opened)
print("------------TestprojectSpiderMiddleware方法from_crawler---------------:")
return s
def process_request(self, request, spider):
# 之前request.Requests自定义可以在这儿自定义user-agent和请求投了
print("------------TestprojectSpiderMiddleware方法process_request因为是定制请求---------------:")
return None
def process_response(self, request, response, spider):
# 处理可能失败的场景 或者重试之类的
print("------------TestprojectSpiderMiddleware方法process_response---------------:")
return response
def process_exception(self, request, exception, spider):
print("------------TestprojectSpiderMiddleware方法process_exception---------------:")
def spider_opened(self, spider):
# 可以使用这个来自己添加日志
spider.logger.info("Spider opened: %s" % spider.name)
print("------------TestprojectSpiderMiddleware方法spider_opened---------------:")
方法
中间件类型 | 方法 | 必须实现 | 调用时机 | 参数 | 返回值 |
---|---|---|---|---|---|
下载器中间件 (Downloader Middleware) | process_request(request, spider) | ❌ 否 | 请求发送到下载器之前 | - request : Request 对象- spider : Spider 实例 | 可选: - None (继续处理)- Response (跳过下载)- Request (替换请求)- Exception (触发错误处理) |
process_response(request, response, spider) | ❌ 否 | 下载器返回响应之后 | - request : 对应的 Request 对象- response : Response 对象- spider : Spider 实例 | 必须返回: - Response 对象- Request 对象(重试或重定向)- 抛出异常 | |
process_exception(request, exception, spider) | ❌ 否 | 下载器或 process_request() 抛出异常时 | - request : Request 对象- exception : Exception 对象- spider : Spider 实例 | 可选: - None (继续处理)- Response (恢复处理)- Request (重试) | |
爬虫中间件 (Spider Middleware) | process_spider_input(response, spider) | ❌ 否 | 响应传递给 Spider 解析之前 | - response : Response 对象- spider : Spider 实例 | - None (继续处理)- 抛出异常(中断处理) |
process_spider_output(response, result, spider) | ❌ 否 | Spider 返回结果(Item 或 Request)之后 | - response : 触发的 Response 对象- result : Item/Request 生成器- spider : Spider 实例 | 必须返回结果生成器(可过滤或修改 Item/Request) | |
process_spider_exception(response, exception, spider) | ❌ 否 | Spider 或 process_spider_input() 抛出异常时 | - response : Response 对象- exception : Exception 对象- spider : Spider 实例 | 可选: - None (继续异常链)- 生成器(返回替代结果) | |
process_start_requests(start_requests, spider) | ❌ 否 | Spider 的 start_requests() 方法调用后 | - start_requests : 初始请求生成器- spider : Spider 实例 | 必须返回请求生成器(可修改初始请求) |
day26代码:pythonPractice: python学习内容练习-代码 - Gitee.com