1 构建Item
在上一篇文章视频网站视频详情页-视频网站-实践-scrapy框架 中我们已经明确了要爬取的内容,下面我们要具体实现内容的抓取。
1.1 创建Item
这里给出Item类源代码如下:
from scrapy import Item, Field
class XpcWorkItem(Item):
# 网页id
article_id = Field()
# 视频id
media_id = Field()
# 信息url
info_url = Field()
# 标题
title = Field()
# 视频appKey
app_key = Field()
# 视频源地址
video_url = Field()
# 封面
cover = Field()
# 分类
category = Field()
# 描述
description = Field()
# 点赞
likes = Field()
# 收藏
collections = Field()
# 播放量
play_counts = Field()
# 发布时间
publish_time = Field()
# 发布地址
ip_location = Field()
1.2 获取目标内容
- 分析:
- 页面内容:我们想要获取的内容,一部分可以在页面上直接找到,比如标题,分类,发布时间等;
- 非页面内容:比如视频源url地址,article_id等,这些需要动态获取。
- 寻找动态获取地址:
-
首先打开f12切换到network标签页,刷新详情页,图示:
-
只有在图示请求地址响应中我们又我们想要的部分内容,那么还有没有更全的响应内容呢?
-
详情页右键->查看网页源代码,搜索appKey相关内容,我们发现图示:
-
我们所需的关于改视频的内容这里都有,这部分内容包含在script标签呢,那么我们下面是直接通过抓取内容呢 还是在看看,有没有更好的方式获取
-
通过查找,我们发现这些数据是通过这个接口获取的https://app.xinpianchang.com/article/%s:%s为之前我们获取的每个视频唯一标识-aid
-
1.3 解析数据接口
之前我们已经解析了详情页的地址,下面我们继续通过详情页响应来解析出数据接口地址,源码如下:
def parse_item(self, response, aid):
yield Request('https://app.xinpianchang.com/article/%s' % aid, callback=self.parse_data, headers=self.headers)
1.4 封装Item
数据接口解析之后,下一步继续解析数据,并封装,先查看下接口响应,如下图:
对比发现,其中发布时间响应数据是10位秒为单位的数字,而我们一般会转换为2020-10-06 18:36:00这种各种的时间字符串传递给数据库处理。索引我们通过ItemLoader来构建Item,代码如下:
from time import time, strftime, localtime
from itemloaders.processors import TakeFirst, MapCompose
from scrapy.loader import ItemLoader
def time_sec2str(sec):
'''
数字时间(10位秒为单位)转换为时间字符串
:param sec: 秒
:return: 时间字符串
'''
print(sec, '='*10)
if not sec:
return strftime('%Y-%m-%d %H:%M:%S', time())
return strftime('%Y-%m-%d %H:%M:%S', localtime(sec))
class XpcWorkLoader(ItemLoader):
default_output_processor = TakeFirst()
publish_time_out = MapCompose(time_sec2str)
- strftime:时间转换函数,时间戳转为指定格式的时间字符串
- TakeFirst():取列表的第一项
- MapCompose:组合
如果对ItemLoader还有啥问题,具体可以查看官方文档或者自行搜索。
ItemLoader搞定了,下面开始封装Item,代码如下:
def parse_data(self, response):
# 产品对象加载器
il = XpcWorkLoader(item=XpcWorkItem(), response=response)
# 响应数据转换为json
ret = json.loads(response.text)
# print(ret['data'])
# 设置产品对象字段
# #id
il.add_value('article_id', ret['data']['id'])
# #视频id
il.add_value('media_id', ret['data']['media_id'])
# #信息url
il.add_value('info_url', 'https://app.xinpianchang.com/article/%s' % ret['data']['id'])
# #视频标题
il.add_value('title', ret['data']['title'])
# #视频appKey
il.add_value('app_key', ret['data']['video']['appKey'])
# #视频源地址
il.add_value('video_url', ret['data']['video']['content']['progressive'][0]['url'])
# #封面
il.add_value('cover', ret['data']['cover'])
# #分类
cat0 = ret['data']['categories'][0]
il.add_value('category', cat0['category_name'] + '-' + cat0['sub']['category_name'])
# #描述
il.add_value('description', ret['data']['content'])
# #点赞
il.add_value('likes', ret['data']['count']['count_like'])
# #收藏
il.add_value('collections', ret['data']['count']['count_collect'])
# #播放量
il.add_value('play_counts', ret['data']['count']['count_view'])
# #发布时间
il.add_value('publish_time', ret['data']['publish_time'])
# #发布地址
il.add_value('ip_location', ret['data']['ip_location'])
return il.load_item()
2 存储
数据有了,下面我们将数据存入数据库,方便其他系统调用,这里我们选择mysql数据库。
2.1 mysql
数据库建库、建表等这里不再赘述,如果有相关问题,可以下面评论留言或者自行查阅相关内容,效果图示:
2.2 pipelines
数据库、表已经创建好了,下面我们需要吧数据存入数据库,需要通过pipeline(管道),代码如下:
import pymysql
class XpcMysqlPipeline:
def __init__(self, host, port, db, user, password):
self.host = host
self.port = port
self.db = db
self.user = user
self.password = password
@classmethod
def from_crawler(cls, crawler):
return cls(
host=crawler.settings.get('MYSQL_HOST', '127.0.0.1'),
port=crawler.settings.get('MYSQL_PORT', 3306),
db=crawler.settings.get('MYSQL_DB'),
user=crawler.settings.get('MYSQL_USER', 'root'),
password=crawler.settings.get('MYSQL_PASSWORD', 'root')
)
def open_spider(self, spider):
self.conn = pymysql.connect(
host=self.host,
port=self.port,
db=self.db,
user=self.user,
password=self.password
)
self.cur = self.conn.cursor()
def close_spider(self, spider):
self.cur.close()
self.conn.close()
def process_item(self, item, spider):
keys = item.keys()
values = list(item.values())
sql = 'insert into video_show({}) values ({}) '.format(
','.join(keys),
','.join(['%s'] * len(values))
)
# sql = 'insert into blog(title, publish, approval, unlike, `comment`, collection) values (%s, %s, %s, %s,
# %s, %s)'
# sql_exe = sql % tuple(val for val in values)
# print(sql_exe, '='*10)
self.cur.execute(sql, values)
self.conn.commit()
# print(self.cur._last_executed)
return item
-
为了后续在添加字段时,不在改动代码,这么我们没有把实际的字段名传入,而是通过字符串模板的方式实现,具体见process_item方法
-
我们把数据库配置信息,放置在settings.py中(具体数值改为自己的),代码如下
# mysql数据库配置 MYSQL_HOST = '127.0.0.1' MYSQL_PORT = 3306 MYSQL_DB = 'py_scrapy_xpc' MYSQL_USER = 'root' MYSQL_PASSWORD = 'root' MYSQL_CHARSET = 'utf-8'
-
构建了pipelines之后,需要在settings.py中开启(具体名称改为自己的),代码如下:
ITEM_PIPELINES = { 'xpc.pipelines.XpcMysqlPipeline': 300, }
3 测试
其他的测试我们这里不详述了,这里只展示下数据库中内容,图示:
4 后记
如果有问题欢迎留言和交流,下面为联系方式和仓库源代码地址。
❓QQ:806797785
⭐️源代码仓库地址:https://gitee.com/gaogzhen/python-study.git