前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >爬虫系列:数据清洗

爬虫系列:数据清洗

原创
作者头像
太后
发布2022-01-12 10:36:54
1.7K0
发布2022-01-12 10:36:54
举报
文章被收录于专栏:短信接收服务

上一期我们讲解了使用 Python 读取 CSV、PDF、Word 文档相关内容。

前面我们已经介绍了网络数据采集的一些基础知识,现在我们将进入高级数据采集部分。到目前为止,我们创建的网络爬虫都不是特别给力,如果网络服务器不能立即提供样式规范的信息,爬虫就不能采集正确的数据。如果爬虫只能采集那些显而易见的信息,不经过处理就存储起来,那么迟早要被登录表单、网页交互以及 Javascript 困住手脚。总之,目前爬虫还没有足够的实力去采集各种数据,只能处理那些愿意被采集的信息。

高级数据采集部分就是要帮你分析原始数据,获取隐藏在数据背后的故事——网站的真实故事其实都隐藏在 Javascript、登录表单和网站反爬措施背后。

数据清洗

到目前为止,我们都没有处理过那些样式不规范的数据,要么使用的是样式规范的数据源,要么就是放弃样式不符合我们预期的数据。但在网络数据采集中,你通常无法对采集的数据样式太挑剔。

由于错误的标点符号、大小写字母不一致、断行和拼写错误等问题,凌乱的数据(dirty data)是网络中的大问题。下面我们就通过工具和技术,通过改变代码的编写方式,帮你从源头控制数据凌乱的问题,并且对已经入库的数据经行清洗。

编写代码清洗数据

和编写异常处理代码一样,你应该学会编写预防型代码来处理意外情况。

在语言学中有一个模型叫 n-gram,表示文本或语言中的 n 个连续的单词组成的序列。再进行自然语言分析时,用 n-gram 或者寻找常用词组,就可以很容易的把一句话分成若干个文字片段。

在接下来的内容我们将重点介绍如何获取格式合理的 n-gram。

下面的代码返回维基百科词条“Python programming language”的 2-gram 列表:

代码语言:txt
复制
from utils import connection_util
代码语言:txt
复制
class DataCleaning(object):
代码语言:txt
复制
    def __init__(self):
代码语言:txt
复制
        self._target_url = 'https://en.wikipedia.org/wiki/python_(programming_language)'
代码语言:txt
复制
        self._init_connection = connection_util.ProcessConnection()
代码语言:txt
复制
    @staticmethod
代码语言:txt
复制
    def ngrams(input_text, n):
代码语言:txt
复制
        split_result = input_text.split(' ')
代码语言:txt
复制
        output = []
代码语言:txt
复制
        for i in range(len(split_result) - n + 1):
代码语言:txt
复制
            output.append(split_result[i:i + n])
代码语言:txt
复制
        return output
代码语言:txt
复制
    def get_result(self):
代码语言:txt
复制
        # 连接目标网站,获取内容
代码语言:txt
复制
        get_content = self._init_connection.init_connection(self._target_url)
代码语言:txt
复制
        if get_content:
代码语言:txt
复制
            content = get_content.find("div", {"id": "mw-content-text"}).get_text()
代码语言:txt
复制
            ngrams = self.ngrams(content, 2)
代码语言:txt
复制
            print(ngrams)
代码语言:txt
复制
            print("2-grams count is: " + str(len(ngrams)))
代码语言:txt
复制
if __name__ == '__main__':
代码语言:txt
复制
    DataCleaning().get_result()

ngrams 函数把一个待处理的字符串分成单词序列(假设所有单词按照空格分开),然后增加到 n-gram 模型形成以每个单词开始的二元数组。

运行程序之后,会有一些凌乱的数据,例如:

代码语言:txt
复制
['web', 'frameworks\nBottle\nCherryPy\nCubicWeb\nDjango\nFastAPI\nFlask\nGrok\nNagare\nNevow\nPylons\nPyramid\nQuixote\nTACTIC\nTornado\nTurboGears\nTwistedWeb\nWebware\nweb2py\nZope']

另外,应为每个单词(除了最后一个单词)都要创建一个 2-gram 序列,所以这个词条里共有 11680 个 2-gram 序列。这并不是一个非常便于管理的数据集!

我们首先使用一些正则表达式来移除转义字符(\n),再把 Unicode 字符过滤掉。我们可以通过下面的函数对之前输出的内容经行清理:

代码语言:txt
复制
import re
代码语言:txt
复制
from utils import connection_util
代码语言:txt
复制
class DataCleaning(object):
代码语言:txt
复制
    def __init__(self):
代码语言:txt
复制
        self._target_url = 'https://en.wikipedia.org/wiki/python_(programming_language)'
代码语言:txt
复制
        self._init_connection = connection_util.ProcessConnection()
代码语言:txt
复制
    @staticmethod
代码语言:txt
复制
    def ngrams(input, n):
代码语言:txt
复制
        input = re.sub('\n+', " ", input)
代码语言:txt
复制
        input = re.sub(' +', " ", input)
代码语言:txt
复制
        input = bytes(input, "UTF-8")
代码语言:txt
复制
        input = input.decode("ascii", "ignore")
代码语言:txt
复制
        print(input)
代码语言:txt
复制
        input = input.split(' ')
代码语言:txt
复制
        output = []
代码语言:txt
复制
        for i in range(len(input) - n + 1):
代码语言:txt
复制
            output.append(input[i:i + n])
代码语言:txt
复制
        return output
代码语言:txt
复制
    def get_result(self):
代码语言:txt
复制
        # 连接目标网站,获取内容
代码语言:txt
复制
        get_content = self._init_connection.init_connection(self._target_url)
代码语言:txt
复制
        if get_content:
代码语言:txt
复制
            content = get_content.find("div", {"id": "mw-content-text"}).get_text()
代码语言:txt
复制
            ngrams = self.ngrams(content, 2)
代码语言:txt
复制
            print(ngrams)
代码语言:txt
复制
            print("2-grams count is: " + str(len(ngrams)))
代码语言:txt
复制
if __name__ == '__main__':
代码语言:txt
复制
    DataCleaning().get_result()

上面的代码首先将内容中的换行符(或者多个换行符)替换成空格,然后把连续的多个空格替换成一个空格,确保所有单词之间只有一个空格。最后,把内容转换成 UTF-8 格式以消除转义字符。

通过上面的几步,我们已经可以大大改善输出结果了,但是还是有一些问题:

代码语言:txt
复制
ALGOL 68,[13] APL,[14] C,[15] C++,[16] CLU,[17] Dylan,[18] Haskell,[19] Icon,[20] Java,[21] Lisp,[22] Modula-3,[16] Perl, Standard ML[14]InfluencedApache Groovy

因此,需要增加一些规则来处理数据。我们可以定制一些规则让数据变得更规范:

  • 剔除单字符的“单词”,除非这个单词是“a”或“i”;
  • 剔除维基百科的引用标记(方括号包裹的数字,入1)
  • 剔除标点符号

现在“清洗任务”列表变得越来越长,让我们把规则都移出来,新建一个函数:

代码语言:txt
复制
import re
代码语言:txt
复制
import string
代码语言:txt
复制
def ngrams(self, input, n):
代码语言:txt
复制
    input = self.clean_input(input)
代码语言:txt
复制
    output = []
代码语言:txt
复制
    for i in range(len(input) - n + 1):
代码语言:txt
复制
        output.append(input[i:i + n])
代码语言:txt
复制
    return output
代码语言:txt
复制
@staticmethod
代码语言:txt
复制
def clean_input(input):
代码语言:txt
复制
    input = re.sub('\n+', " ", input)
代码语言:txt
复制
    input = re.sub('\[[0-9]*\]', "", input)
代码语言:txt
复制
    input = re.sub(' +', " ", input)
代码语言:txt
复制
    input = bytes(input, "UTF-8")
代码语言:txt
复制
    input = input.decode("ascii", "ignore")
代码语言:txt
复制
    input = input.split(' ')
代码语言:txt
复制
    clean_input = []
代码语言:txt
复制
    for item in input:
代码语言:txt
复制
        # string.punctuation 获取所有的标点符号
代码语言:txt
复制
        item = item.strip(string.punctuation)
代码语言:txt
复制
        if len(item) > 1 or (item.lower() == 'a' or item.lower() == 'i'):
代码语言:txt
复制
            clean_input.append(item)
代码语言:txt
复制
    return clean_input

这里用 import string 和 string.punctuation 来获取 Python 所有的标点符号。我们可以在 Python 命令行里面查看标点符号有哪些:

代码语言:txt
复制
import string
代码语言:txt
复制
print(string.punctuation)
代码语言:txt
复制
!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~

在循环体中用item.strip(string.punctuation)对内容中的所有单词进行清洗,单词两端的任何标点符号都会被去掉,但带连字符的单词(连字符在单词内部)任然会保留。

本期关于数据清洗就是如上内容,在接下来的内容中我会讲解数据标准化,以及存储的数据如何清洗。

以上的演示源代码托管于 Gihub,地址:https://github.com/sycct/Scrape_1_1.git

如果有任何问题,欢迎大家 issue。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 数据清洗
    • 编写代码清洗数据
    相关产品与服务
    代码托管
    CODING 代码托管(CODING Code Repositories,CODING-CR)是为开发者打造的云端便捷代码管理工具,旨在为更多的开发者带去便捷、高效的开发体验,全面支持 Git/SVN 代码托管,包括代码评审、分支管理、超大仓库等功能。
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档