分布式爬虫之数据处理

redis作为缓存,mysql用来做数据实际存储

import ast
import re
import time
import pymysql
import redis

class Settings(object):
#redis 的连接配置
redis_conn_config = dict(
host=‘localhost’,
port=6379,
db=‘0’,
password=None,
encoding=‘utf-8’,
decode_responses=True,
)

# redis 的键名(用set集合做缓存)
redis_key_name = 'data'
# 写入redis异常信息的 存储文件
redis_error_file = 'redis_error.log'
# 每次从 redis中取多少量的数据
redis_pop_num = 100


# mysql的连接配置,并去创建相应的数据库与表
mysql_conn_config = dict(
    host='xxxxxxxxxxx',
    port=3306,
    user='xxx',
    password='xxxx',
    # 选择数据库,自己创建
    database='xxxxx',
    charset='utf8',

)

# mysql的连接表名, 写自己创建的数据库下对应的数据表名
mysql_table_name = ''
# mysql中过滤的字段, 进行自定义的设置
mysql_filter_name = ['']
# mysql 异常 信息的保存文件
mysql_error_file = 'mysql_error.log'
# 等待多少秒后 redis中仍无数据,就停止服务
exit_wait_seconds = 10

class Pipeline_to_redis_server(object):
“”“redis管道类,将数据写入到 redis中”""
#建立redis的连接
def init(self, settings=Settings):
self.settings = Settings
self.redis_conn = redis.StrictRedis(**self.settings.redis_conn_config)

# 向redis中加入数据
def add_data(self,data_s:list):

    # 拼接 key
    redis_sql = 'sadd s%' %self.settings.redis_key_name + ' '

    # 遍历数据 data_s 是一个 列表中 嵌套的 字典数据,遍历出来的是 每一个个字典,
    for data in data_s:
        # \s代表正则表达式中的一个空白字符(可能是空格、制表符、其他空白)。
        data_str = re.sub('\s', '', str(data))
        redis_sql += data_str + ' '
    # 执行sql语句和异常处理
    try:
        # 执行sql语句,将数据添加到 redis的集合中,集合有去重的功能
        self.redis_conn.execute_command(redis_sql)
    except:
        # 出现写入数据异常,将该数据的 信息写入到 log日志中
        with open(self.settings.redis_error_file, 'a') as f:
            f.write(str(data_str) + '\n')

class Redis_to_mysql_server(object):
“”“将缓存数据从redis中保存到mysql中”""
def init(self, setting=Settings):
# 加载redis和mysql的配置文件
self.settings = setting
# 创建redis连接对象
self.redis_conn = redis.StrictRedis(**self.settings.redis_conn_config)
# 创建mysql的连接对象
self.mysql_conn = pymysql.Connection(**self.settings.mysql_conn_config)
# 创建mysql的游标对象
cs = self.mysql_conn.cursor()
cs.execute(‘show columns from %s’ % self.settings.mysql_table_name)
# 结果为一个元组里面嵌套着小元组
# 数据格式为 ((‘id’, ‘int(11)’, ‘NO’, ‘PRI’, None, ‘auto_increment’), (‘category1’, ‘varchar(100)’, ‘YES’, ‘’, None, ‘’), (‘category2’, ‘varchar(100)’, ‘YES’, ‘’, None, ‘’), (‘category3’, ‘varchar(100)’, ‘YES’, ‘’, None, ‘’), (‘book_name’, ‘varchar(200)’, ‘YES’, ‘’, None, ‘’))
table_data_s = cs.fetchall()
self.column_name_s = []
for table_data in table_data_s:
# table_data[0]:‘id’,‘category1’,即数据库中的字段名
column_name = table_data[0]
# self.settings.mysql_filter_name:条件过滤字段,可以设定哪些字段不需要
if column_name not in self.settings.mysql_filter_name:
self.column_name_s.append(column_name)
cs.close()

def run(self):
    # 创建mysql的游标对象
    cs = self.mysql_conn.cursor()

    single_field = ''
    # 修改 column_name_s列表,因为列表数不能再 sql语句中操作single_field
    for field in self.column_name_s:
        single_field += '%s,' % field
    sql_base = 'insert into %s (%s) values' %(self.settings.mysql_table_name, single_field[0:-1])
    # 初始化开始的时间,是为了防止 redis从一开始就没有数据,依然能够执行到 下面的没有数据的逻辑中的 execute_time
    # 保证代码的完整性
    execute_time = time.time()
    while True:
		# self.settings.redis_key_name:redis的键名
        # self.settings.redis_pop_num:要从redis的集合中拿出的数据的 条数
        # redis_data_s:返回的结果是: 对应键下的 100 行数据
        redis_data_s = self.redis_conn.execute_command('spop %s %s' %(self.settings.redis_key_name, self.settings.redis_pop_num))
        # 如果有数据
        if redis_data_s:
            # 计算有数据开始的时间
            execute_time = time.time()
            total_value = ''
            for redis_data in redis_data_s:
			#要用 ast还原成 字典
                data_dict = ast.literal_eval(redis_data)
                single_value = ''
                for column_name in self.column_name_s:
                    if column_name in data_dict.keys()
                        single_value += '"%s",' % data_dict[column_name]
                    else:
                        single_value += '"",'
                total_value += '(%s),' % single_value[0:-1]
            sql_inster = sql_base + total_value[0:-1]
            # 执行sql语句
            try:
                # 通过游标对象执行 sql语句
                cs.execute(sql_inster)
                self.mysql_conn.commit()
            except:
                # 如果出现错误 那么 将出现错误的数据 写入到 日志中
                with open(self.settings.mysql_error_file, 'a') as f:
                    f.write(str(redis_data_s) + '\n')
        # 如果没有数据
        else:
            # 获取没有数据时的时间
            empty_time = time.time()
            # 判断是否满足结束的条件,是 没有数据的时间
            # self.settings.exit_wait_seconds:这里设置的10秒,超过这个时间如果还没有数据 就表明 数据已读取完。
            if empty_time - execute_time > self.settings.exit_wait_seconds:
                return "finished"

测试运行

if name == ‘main’:
redis_server = Pipeline_to_redis_server(Settings)
setting = Settings()
setting.mysql_table_name = ‘t_data’
setting.mysql_filter_name = [‘id’]

server = Redis_to_mysql_server(setting)
server.run()
Python网络爬虫与推荐算法新闻推荐平台:网络爬虫:通过Python实现新浪新闻的爬取,可爬取新闻页面上的标题、文本、图片、视频链接(保留排版) 推荐算法:权重衰减+标签推荐+区域推荐+热点推荐.zip项目工程资源经过严格测试可直接运行成功且功能正常的情况才上传,可轻松复刻,拿到资料包后可轻松复现出一样的项目,本人系统开发经验充足(全领域),有任何使用问题欢迎随时与我联系,我会及时为您解惑,提供帮助。 【资源内容】:包含完整源码+工程文件+说明(如有)等。答辩评审平均分达到96分,放心下载使用!可轻松复现,设计报告也可借鉴此项目,该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的。 【提供帮助】:有任何使用问题欢迎随时与我联系,我会及时解答解惑,提供帮助 【附带帮助】:若还需要相关开发工具、学习资料等,我会提供帮助,提供资料,鼓励学习进步 【项目价值】:可用在相关项目设计中,皆可应用在项目、毕业设计、课程设计、期末/期中/大作业、工程实训、大创等学科竞赛比赛、初期项目立项、学习/练手等方面,可借鉴此优质项目实现复刻,设计报告也可借鉴此项目,也可基于此项目来扩展开发出更多功能 下载后请首先打开README文件(如有),项目工程可直接复现复刻,如果基础还行,也可在此程序基础上进行修改,以实现其它功能。供开源学习/技术交流/学习参考,勿用于商业用途。质量优质,放心下载使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值