美文网首页
python爬虫开发规范

python爬虫开发规范

作者: 修行的修行 | 来源:发表于2021-11-14 20:07 被阅读0次

前言

实现一个爬虫需求很简单。但是管理很多爬虫是有以下难点的:

1.在其爬取的网页结构改变的时候。及时发现,且不因某一字段而影响整体数据获取

2.爬虫代码逻辑清晰,易于开发人员修改。特别是在开发人员变动的情况下

3.爬虫后台运行失败时能够查询到详细的日志,定位问题

4.只有将业务逻辑和代码逻辑分离开,才能提升开发效率和代码质量。特别是日志记录方面

常用库

# 报错重试
from retry import retry

# 请求
import requests

# 解析
from lxml import etree
import json
import re

爬虫模板

父类工具类

一些爬虫可以复用的函数,如:解析xml中的数据,解析字典中的数据,数据存储

class Spider(object):
    def _parse_xml_data(self, data_xml, xpath_str):
        try:
            use = data_xml.xpath(xpath_str)[0].strip()
            return use
        except:
            return ''

    def _parse_dict_data(self, data_dict, *args):
        # 解决字典中不存在key的情况,适用于可以查询不到的情况
        try:
            use = ''
            for i in args:
                use = data_dict[i]
                data_dict = use
            return use
        except:
            return ''

    def _save_data(self, total_list):
        pass

子类爬虫类

实现某一网站的爬虫,建议一个网站一个文件,实现一个类,类中有该网站各数据的对应爬取函数。

platform_name = 'game'
class GameSpider(Spider):
    def __init__(self):
        super().__init__()
        self.headers = {}

    @log()
    def main(self):

        @log()
        @retry(tries=3, delay=5)
        def __get_data_list(url):
            res = requests.get(url, headers=self.headers)
            comments_list = []
            if comments_list:
                return comments_list
            else:
                raise ValueError(res.text)

        @log()   
        def __parse_data(data):
            return temp_dict

        url_list = []
        total_list = []
        for url in url_list:
            try:
                data_list = __get_data_list(url = url)
            except:
                continue
            for data in data_list:
                temp_dict = __parse_data(data = data)
                total_list.append(temp_dict)
        self._save_data(total_list)

爬虫步骤

爬虫基本上就分为3个步骤: 请求获取到有效数据=>数据解析=>数据存储

1.请求获取到有效数据

请求外部网址的痛点是,请求网址可能会失败需要重试,所以将请求外部网址+获取数据列表剥离出来形成一个函数,用retry装饰器来实现重试,避免突然的网络问题导致的获取数据失败。

任务文件

try:
    data_list = self.__get_data_list(url)
except:
    continue

请求外部网址+获取数据列表

# html版
@log()   
@retry(tries=3, delay=8)
def __get_data_list(url):
    res = requests.get(url, headers=self.headers)
    use = etree.HTML(res.text)
    comments_list = use.xpath('//li')
    if comments_list:
        return comments_list
    else:
        raise ValueError(res.text)

# json版
@log()   
@retry(tries=3, delay=8)
def __get_data_list(url):
    res = requests.get(url, headers=self.headers)
    data = json.loads(res.text)
    if 'viewpoints' in data.keys() and data['viewpoints']:
        return data['viewpoints']
    else:
        raise ValueError(res.text)

2.数据解析

# html版

@log()  
def __parse_data(self, xml_data):
    player = self._parse_xml_data(xml_data, 'div[@class="detail"]/p[@class="from"]/span[@class="name"]/text()')
    content = self._parse_xml_data(xml_data, 'div[@class="detail"]/p[@class="text"]/text()')
    temp_dict = {
        '用户名': player,
        '评论': content,
    }
    return temp_dict 

# json版

@log()  
def __parse_data(self, data):
    data = {
        'info':{
            'name': 'Tom'
        }
        'list':[
            {'socre': 99}
        ]
    }
    temp_dict = {
        'name': self._get_dict_data(data, 'info', 'name')
        'score': self._get_dict_data(data, 'list', 0, 'score')
    }
    return temp_dict

3.数据存储

数据存储一般是比较通用的,可以写在父类工具类中

日志记录

日志记录如果不规范,代码的各处会散步着log.info****、log.error(代码混乱),写代码的时候需要想哪些该记哪些不该记,没有工程化这些思路。加上爬虫文件多了的话找日志所在的位置也十分痛苦。

需要考虑2点:

1.多爬虫文件、多函数。这涉及到日志文件的管理。

最终是决定以 爬取平台 为文件夹名 ,日期+执行函数 为日志名

2.代码流程日志、执行报错日志。代码流程日志让你知道代码执行到什么位置了(有时候也会想看爬虫是否还在跑),执行报错日志记你的爬虫为何报错终止。

image

2021-11-12crawl_comments_and_user_im.log ,记录代码流程

2021-11-12taptap_error.log,记录代码主函数报错

2021-11-12taptap.log,记录一些共用函数的代码流程(即一个子函数可能多个主函数都在用)

def log_main_func(platform_name):
    """
    记录导致主函数(某个爬虫类的主任务函数)终止的报错日志
    :param platform_name: 爬取的平台名称
    :return:
    """
    pass

def log_son_func(platform_name, main_func_name, input_flag=True, output_flag=True):
    """
    记录子函数的日志
    :param platform_name: 爬取的平台名称
    :param main_func_name: 主函数名称(如果是公用子函数main_func_name就填platform_name)
    :param input_flag: 是否记录入参
    :param output_flag: 是否记录返回
    :return:
    """
    pass

通过这种方式,所有的日志记录全部通过装饰器来控制,开发的时候只需要想清楚哪些代码应该剥离成一个函数,记录它的入参和返回。

装饰器中可控制 日志所在的文件夹名日志名是否记录入参、是否记录返回。

相关文章

网友评论

      本文标题:python爬虫开发规范

      本文链接:https://www.haomeiwen.com/subject/thoqtrtx.html