创建框架和项目
### 1. 创建虚拟环境
conda create -n spiderScrapy python=3.9
### 2. 安装scrapy
pip install scrapy==2.8.0 -i https://pypi.tuna.tsinghua.edu.cn/simple
### 3. 生成一个框架并进入框架
scrapy startproject my_spider
cd my_spider
### 4. 生成项目
scrapy genspider Qingting http://http://m.qingting.fm/rank/
### 5. 重新安装Twisted指定版本
pip install Twisted==22.10.0
### 6. 启动项目
scrapy crawl baidu
这里创建了一个qingting的爬虫项目
-
启动框架后会自动调用parse方法
-
parse方法是scrapy框架的回调方法,当启动scrapy框架后:
- scrapy对start_urls类属性进行迭代并获取将要请求的地址
- 获取到地址后,scrapy会自动发送请求
- 获取到响应对象后会调用parse方法并将获取到的response对象传递过来
-
response对象中常用的属性
print('响应url', response.url) print('响应头', response.headers) print('响应状态码', response.status) print('响应体', response.body.decode('utf-8')) print('请求地址', response.request.url) print('请求头', response.request.header)
后面开发过程使用cmdline进行启动
from scrapy import cmdline
...
...
...
if __name__ == '__main__':
cmdline.execute("scrapy crawl qingting".split())
1. 在parse中解析response响应内容
2. 使用yield关键字将解析好的数据提交给管道pipelines模块进行存储
#qingting.py
class QingtingSpider(scrapy.Spider):
name = "qingting"
allowed_domains = ["m.qingting.fm", "pic.qtfm.cn"] # 请求白名单
start_urls = ["http://m.qingting.fm/rank/"]
# 启动框架后会自动调用parse方法
def parse(self, response: HtmlResponse, **kwargs):
"""
parse方法是scrapy框架的回调方法,当启动scrapy框架后:
1. scrapy对start_urls类属性进行迭代并获取将要请求的地址
2. 获取到地址后,scrapy会自动发送请求
3. 获取到响应对象后会调用parse方法并将获取到的response对象传递过来
"""
"""
response对象中常用的属性
print('响应url', response.url)
print('响应头', response.headers)
print('响应状态码', response.status)
print('响应体', response.body.decode('utf-8'))
print('请求地址', response.request.url)
print('请求头', response.request.header)
"""
a_list = response.xpath('//div[@class="rank-list"]/a')
for item in a_list:
rank_num = item.xpath('./div[@class="badge"]/text()').extract_first() # 排名
title = item.xpath('.//div[@class="title"]/text()').extract_first() # 标题
img_url = item.xpath('./img/@src').extract_first() # 图片地址
desc = item.xpath('.//div[@class="desc"]/text()').extract_first() # 描述
play_number = item.xpath('.//div[@class="info-item"][1]/span/text()').extract_first() # 播放数
# 下一步:
# 使用yield关键字将解析好的数据提交给管道pipelines模块进行存储
yield {
"type": "info",
"title": title,
"img_url": img_url,
"rank_num": rank_num,
"desc": desc,
"play_number": play_number
}
# 自行构造request请求并交给下载器下载
"""
callback: 指定解析方法
cb_kwargs: 如果解析方法中存在形参,则可以通过cb_kwargs传递,传递值的类型必须是字典,字典中的key必须与形参名称保持一致
"""
print(img_url)
yield scrapy.Request(img_url, callback=self.parse_img, cb_kwargs={'img_name': title})
def parse_img(self, response, img_name):
yield {
'type': 'img',
'img_name': f"{img_name}.png",
'img_content': response.body
}
## pipelines.py
import os
import pymongo
class FmPipeline:
def process_item(self, item, spider):
"""
如果想在管道模块中打印parse方法返回的数据需要在配置文件中激活管道
:param item: parse方法返回的值
:param spider: 定义的爬虫名称
:return:
"""
type_ = item.get('type')
if type_ == "img":
download_path = os.path.join(os.getcwd(), 'download')
if not os.path.exists(download_path):
os.mkdir(download_path)
img_name = item.get('img_name')
image_content = item.get('img_content')
if img_name:
with open(f"{download_path}/{img_name}".replace("|",'_'), 'wb') as file:
file.write(image_content)
print('图片保存成功', img_name)
elif type_ == "info":
mongo_client = pymongo.MongoClient('mongodb://root:123456@124.70.4.*:27017') # 连接自己的数据库
collection = mongo_client['py_spider']['fm']
collection.insert_one(item)
print('数据插入成功')
else:
print('其他未知的数据类型')
## 警告处理
2024-03-09 14:34:17 [py.warnings] WARNING: D:\software\miniconda3\envs\spiderScrapy\lib\site-packages\scrapy\selector\unified.py:83: UserWarning: Selector got both text and root, root is being ignored.
super().__init__(text=text, type=st, root=root, **kwargs)
## 降级parsel包
pip install parsel==1.7.0