数据整理技巧笔记一

非结构化数据整理

Posted by HugoNgai on November 11, 2019

前言

在写爬虫抓取信息的时候,需要对信息进行初步的整理,然后才落盘数据。这时候,我们需要用程序来将凌乱的数据先进行一次结构化,方便我们对数据进行写库。在这里分享一个简单数据整理技巧。

​ 在进行分享前,先拿一个案例作为例子:

example_one

​ 以某网站为例,这是一个目录表的网页结构,ul标签下为一级目录,每个目录有一个对应的id,下面的每一个div标签为该目录对应的子目录。那么我们应该如何去对这个目录结构进行一个结构化处理呢?

​ 开始前,先介绍一下python的dict数据结构。因为这里爬虫使用的是python,所以我选择使用python下的dict结构对数据进行一个结构化的处理。

Dict字典

​ 字典是python中能用关键字来查询相关内容的数据结构。它通过key-value键值对的形式来进行构建。因为在这个例子中,我们需要通过id来进行信息的匹配,选择使用字典的优势在于,字典存储起来可读性更强,最关键的地方,字典底层是通过hash实现的,如果我们以id作为key,那么在查询key的时候的时间复杂度为O(1),使用起来非常方便高效。具体字典的相关用法,这里就不详细介绍了,可以Google一下进行了解。

正文

​ Talk is cheap. Show me the code. 话不多说直接上代码。

  • Step one

    首先我们使用一个数组来存储最终结构话的结果。(这里使用xpath对网页信息进行提取)

    # define result list and cat2 dict
    result_list = list()
    cat2_dict = dict()
    cat_list = response.xpath('//div[@class="header"]/div')
    cat_1_list = cat_list[0].xpath('./ul[@class="top-menu desktop"]/li')
    for cat1 in cat_1_list:
        cat_1 = html.unescape(cat1.xpath('./a/text()').extract_first())
        cat_1_url = urljoin(self.base_url, cat1.xpath('./a/@href').extract_first())
        cat_1_id = cat1.xpath('./@data-id').extract_first()
        result_list.append({
            'cat_1': cat_1,
            'cat_1_url': cat_1_url,
            'cat_1_id': cat_1_id
        })
    

    OK, 完成对一级目录的信息存储。接下来的关键在于对二级目录的匹配存储。

  • Step two

    在操作前,先思考一个问题。如何进行二级目录与一级目录的匹配。很显然我们需要用到一级目录中的id。那么这个时候dict中的key就发挥作用了。在抓取二级目录的时候,可以把每个二级目录的id作为一个key,然后用一个临时数组来存储该二级目录的全部信息,并把这个数组做为value与该key作为键值对形式存储下来。

    for cat2_divs in cat_list[1:]:
        tmp_cat2_list = list()
        index = cat2_divs.xpath('./@data-id').extract_first()
        cat2_list = cat2_divs.xpath('.//ul[contains(@class, "sublist")]/li')
        for cat2 in cat2_list:
            cat_2 = html.unescape(cat2.xpath('./a/text()').extract_first())
            cat_2_url = urljoin(self.base_url, cat2.xpath('./a/@href').extract_first())
            tmp_cat2_list.append({
                 'cat_2': cat_2,
                 'cat_2_url': cat_2_url
            })
            cat2_dict.update({
                 index: tmp_cat2_list
            })
    

    好了,这一步完成以后,cat2_dict里面已经按照每个id及其对应的二级目录存储了所有的二级目录信息。

  • Step three

    完成了一级目录和二级目录的存储,这时候就要把它们匹配起来,形成结构化的数据。

    for item in result_list:
        index = item.get('cat_1_id')
        cat_2_list = cat2_dict.get(index)
        item.update({
            'cat_2_list': cat_2_list
        })
    

​ 至此,对于这个网站的目录信息已经完成了结构化的处理,最终处理完成后的数据结构如下:

[ { 'cat_1': cat_1,
    'cat_1_url': cat_1_url,
    'cat_1_id': cat_1_id,
    'cat_2_list': [ { 'cat_2': cat_2,
                      'cat_2_url': cat_2_url
                     },
                   ...
                  ]
    }
    ...
]

​ 处理完后,目录信息以JSON的格式存储了下来,那么在后期对数据进行落盘或其他处理的时候,就会方便很多了。这里的例子是个二级目录的例子,如果目录更加多层次,一样可以通过这种形式将其存储为JSON的格式。

整个方式处理下来,时间复杂度为O(1)。

结尾

​ 对于各种各样纷繁复杂的数据信息,我们需要不断去学习和掌握对无序混乱的非结构化数据进行处理,方便我们后期对数据的存储和应用,后续会继续分享自己学习过程中的一些技巧。