数据准备篇:没有数据怎么办,当然自己爬喽

img

智慧,不是死的默念,而是生的沉思。 ——斯宾诺莎

俗话说:将军难打无兵之仗,巧妇难为无米之炊。

意思就是说,专业技能和素养都具备了,但是没有对应的资源供你调度,那也是空有一身本领而难倒英雄汉。

对于数据分析,特别是在入门阶段,如果没有对应的数据供练习实战,那终归会停留在纸上谈兵阶段而无法知悉代码背后的秘密。模拟真实数据分析场景至关重要,但是数据又该从何而来呢?

作为程序员,开源使人进步。开源的数据库同样如此,这里力荐几个公开数据集供大家选择:

1. 开源数据国外篇

  • GitHub awesome-public-datasets

    awesome-public-datasets(https://github.com/awesomedata/awesome-public-datasets),一个 GitHub 上开源的数据资源库,涉及到的领域涵盖了农业、生物学、气候、计算机网络、数据科学、地球科学、经济学、教育、能源、金融学、地图、图像处理、机器学习、自然语言、神经科学、物理学、心理学、社会科学…「国内访问 Github 会比较慢,这里小伙伴可以访问这个链接下载:https://aiyc.lanzous.com/i1OXUfi13yb

    image-20200811082824170

  • 亚马逊跨学科数据平台

    亚马逊跨学科数据平台(https://registry.opendata.aws/ ),包含化学、生物学、经济学、天文学等多个领域的数据集。同样是公开数据集,涉及领域较少但是非常权威。不过下载前需要先注册。

    image-20200811083107565

2. 开源数据国内篇

  • 国家数据 National Data

    国家数据库( http://data.stats.gov.cn/ )信息内容涵盖范围全面、详实,具有很高的实用性;其数据范围和国民生活息息相关,并且具有很高的权威性,基本只要和国情相关的信息都会在里边发布,比如地区房价、工业、能源、居民消费总额、房地产投资甚至食品的平均价格。

    image-20200811083254163

  • 国家统计局数据

    国家统计局( http://www.stats.gov.cn/ )的信息的信息通常都是基于统计之后的宏观信息,并且按照工业门类以及年限、地域等指标做了归类,方便大家查阅、引用以及做进一步分析

    image-20200811083440789

    国家统计局官网的底部,预留了各个地方、其他国家、国际组织的官方链接,有兴趣的朋友也可以去这里淘金。

3. 定向网站的数据采集

但是对于更一般的场景,部分朋友希望能够采集到更加专业的信息。

  • 比如想研究股票信息,需要去股票网站采集交易、价格等数据;
  • 想研究房地产信息,可以去链家、贝壳等网站采集买卖详单;
  • 想要研究社会舆情,可以去新闻门户网站采集新闻类信息。

数据量太大怎么办?

门户网站没有提供下载链接。对于已经学习了 Python 的朋友们来讲,没有技术解决不了的问题,如果有,那就是技术还需要操练。

这里我们提供两种解决方案:

  • 八爪鱼在线定向采集网站

    八爪鱼( https://www.bazhuayu.com/ )是一款免费的数据采集工具,而且没有功能限制,几乎所有网站都能采集,最大的特点是简单方便,免费采集几万条数据没压力。当然如果需要更大批次的数据、更高的采集效率,则需要选择付费增值服务。

    image-20200811083717484

  • 编写个人爬虫程序

    如果上面的手段都解决不了问题,那么只有祭出我们终极武器啦——编写爬虫程序。

    八爪鱼也是一款可轻度定制的爬虫程序,只不过为了适应更广的应用需求,智能程度以及采集效率并不高,而且无法完成一些深入的定制。

    对付简单任务还行,对付稍微复杂的任务,要么付费,要么歇菜了。

    其实爬虫并没有那么神秘,简单来说,爬虫就是一款可重复对目标网站进行数据采集的轻量级程序。

    比如,我想采集北京正在热映的电影清单,我们打开豆瓣北京的首页( https://movie.douban.com/cinema/nowplaying/beijing/ ),可以看到如下:

    image-20200811083926449

    我希望开发一个程序,能够一键采集这个网页上的信息,包括电影名称,电影评分,以及影片图片链接。

    在正式开始我们的爬虫之前,我们先来探讨一个问题,什么是浏览器?

    官方给的定义是,一种用于检索并展示 web 信息资源的应用程序。在我们浏览豆瓣-北京首页的时候,豆瓣服务器根据已经建立的数据传输链路,把电影的信息传递给我们的本地电脑。在本地获取到这些信息后,浏览器通过一定的规则,或重排版,或解码,最终解析成为我们看到的这个样子(见上图)。

    那爬虫呢?

    爬虫就是自动到网页上去采集我们需要的信息?这个表述并不准确。爬虫是我们利用 Python 搭建的一个网络应用服务,它把自己伪装成浏览器,向目标服务器发送请求,并与之建立数据传输的链路。但是与普通浏览器不同的是,爬虫只会解析网站中我们关注的信息,并保存起来(或者直接打印),其他的弃之不用。

    所以从这角度看,简单爬虫可以分为三个关键步骤:

    1. 伪装成浏览器,从目标服务器获取想要的数据;
    2. 建立解析规则,从上一步获取的数据中解析出关注的信息;
    3. 打印或保存。

3.1 伪装成浏览器,从目标服务器获取想要的数据

在这之前,我们先看一下,我们经常浏览的网页页面的真实面目。这里我以 Chrome 为例,做一个演示。

点击 Chrome 的折叠菜单,继续选择 更多工具 > 开发者工具 ,在跳出的隐藏页面中,选择 Elements 菜单,示意如下:

图片描述

因此,第一步我们的目标,就是先通过 Python,构建一个简单应用,并成功抓取网页的页面内容。这里给大家介绍一个工具 requests ,这个工具通过简单的命令就可以模仿浏览器向服务器发送 get 请求,并反馈服务器的返回数据。requests 可以通过 PIP 工具快速安装:

C:\Users\Administrator>pip install requests

完成安装后,我们做一个简单测试,在 Notebook 中输入:

# 导包
import requests
# url为目标网址
url = "https://movie.douban.com/cinema/nowplaying/beijing/"
# 通过requests库,发起一个url请求。把目标服务器的返回值赋值给response
response = requests.get(url)
# text为response的属性,表示返回值的正文内容
print(response.text)
Out:(仅显示部分关键信息,供参考)
<!DOCTYPE html>
……    
……
……
    <li
        id="30481973"
        class="list-item"
        data-title="决胜时刻"
        data-score="7.1"
        data-star="35"
        data-release="2019"
        data-duration="140分钟"
        data-region="中国大陆"
        data-director="黄建新 宁海强"
        data-actors="唐国强 / 刘劲 / 黄景瑜"
        data-category="nowplaying"
        data-enough="True"
        data-showed="True"
        data-votecount="3581"
        data-subject="30481973"
        >
        <ul class="">
            <li class="poster">
                <a href="https://movie.douban.com/subject/30481973/?from=playing_poster" class=ticket-btn target="_blank" data-psource="poster">
                    <img src="https://img1.doubanio.com/view/photo/s_ratio_poster/public/p2568497857.jpg" alt="决胜时刻" rel="nofollow" class="" />
                </a>

    ……    

从上面的请求内容可以看到电影名称:决胜时刻,主演:唐国强 / 刘劲 / 黄景瑜,导演:黄建新 宁海强等信息。

到这里呢,第一步中最关键的一步基本完成,但是还要做一些简单的包装。

我们都知道,如果网页打不开了,常常会看到浏览器返回 404 not found

这里的 404 表示的是状态码,说明这个链接失效了。

那如果网页是正常的呢,网页返回的状态码是 200

因此我们做一个简单的判断,如果网页一切正常(状态码 200 ),则返回网页的内容(字符串类型);如果网页不正常(状态码不是 200 ),则返回 None ,防止程序报错。

# 这里是requests自带的一个请求异常错误
from requests import RequestException

# 封装一个名为get_page的函数,用来获取网页的内容,以文本形式返回。如果网页状态码不为200,则返回空值
# 若是请求异常,同样返回空值
def get_page(url):
    try:
        response = requests.get(url)
        if response.status_code == 200:
            return response.text
        return None
    except RequestException:
        return None
url = "https://movie.douban.com/cinema/nowplaying/beijing/"
html = get_page(url)
html

依次执行这两步程序,可以打印出页面的内容。效果这里就不展示了,请大家自行实践。

建立解析规则,从上一步获取的数据中解析出关注的信息

在不借助外力的情况下,从一大长串字符串中提取目标信息,有什么方法?有经验的朋友一定能够猜到,用正则匹配。没错,这基本是一个万能的方法,但是比较考验基本功。

我们总览上一步得到的 html 的打印值,一定可以找到电影的信息都放在 <li> 以及 <img> 2 个标签中,那我们就是写一个正则,把这2个标签中,我们想要的电影名称、电影评分、电影图片超链接提取出来。但是这里要注意几个问题:

从打印值可以看出,字符串是换行的,正则需要跨行匹配。我们在匹配语句中加上 re.S 就可以了;

一共有几十个电影名录,那就说明每一个电影都有和其对应的 <li> 标签以及 <img> 标签。因此我们需要抑制正则匹配的贪婪性。即只匹配最近字符,做最小匹配。我们用 .* 表示匹配任意字符尽可能多的次数,用 .*? 表示最小匹配任意字符;

分析到这里,一切基本明了了,剩下就是写的问题了。

# 导入正则包
import re
# 根据上面的分析过程,构建匹配规则。其中()表示分组,并按照分组输出匹配结果
pattern = re.compile('<li.*?list-item.*?data-title="(.*?)".*?data-score="(.*?)".*?>.*?<img.*?src="(.*?)".*?/>', re.S)
# 用findall函数进行规则与字符串的匹配,并按照顺序返回全部的匹配结果,返回结果为list类型
items = re.findall(pattern, html)
# 打印items的变量类型,在notebook中,print()可以省略
type(items)
Out: list
len(items)
Out: 64
items[0]
Out:
    ('决胜时刻',
     '7.1',
     'https://img1.doubanio.com/view/photo/s_ratio_poster/public/p2568497857.jpg')

从执行结果可以看出来,一共匹配上了64个结果,其中第一个结果我们做了打印预览,从 items[0] 的结果看,这应该是个元祖。

解析过程基本分析清楚了,我们构建一个函数来封装这个规则解析过程,其中函数的输入是 html 网页内容,输出是匹配的结果。

# 对网页文本内容进行解析。封装一个名为parse_page的函数,用正则来解析HTML。
def parse_page(html):
    pattern = re.compile('<li.*?list-item.*?data-title="(.*?)".*?data-score="(.*?)".*?>.*?<img.*?src="(.*?)".*?/>', re.S)
    items = re.findall(pattern, html)

    # 通过上一步的测试,我们知道了items长度为64。为了优化内存,这里构建了一个迭代器,在下一步打印的时候,有for循环来读取这个迭代器
    for item in items:
        yield{
            'title': item[0],
            'score': item[1],
            'image': item[2],}

打印预览

构建一个循环,逐个打印输出结果:

for item in parse_page(html):
    print(item)
Out:
    {'title': '决胜时刻', 'score': '7.1', 'image': 'https://img1.doubanio.com/view/photo/s_ratio_poster/public/p2568497857.jpg'}
    {'title': '小Q', 'score': '7.0', 'image': 'https://img1.doubanio.com/view/photo/s_ratio_poster/public/p2566474488.jpg'}
    {'title': '友情以上', 'score': '6.6', 'image': 'https://img3.doubanio.com/view/photo/s_ratio_poster/public/p2565511423.jpg'}
    {'title': '罗小黑战记', 'score': '8.2', 'image': 'https://img3.doubanio.com/view/photo/s_ratio_poster/public/p2568288336.jpg'}
    ……
    {'title': '红色娘子军', 'score': '7.2', 'image': 'https://img3.doubanio.com/view/photo/s_ratio_poster/public/p2044374611.jpg'}
    {'title': '五朵金花', 'score': '8.0', 'image': 'https://img1.doubanio.com/view/photo/s_ratio_poster/public/p2529223569.jpg'}

整个爬虫的流程到这里就分析结束了,是不是很简单?用这个思路,朋友们去采集一些简单的网站,比如大部分政府网站、豆瓣、链家等等,都是没有问题的。

当然了,今天只是浅尝辄止,爬虫可以还有很多内容需要去学习,比如如何绕过反爬策略,如何高效地解析网页,如何保存,如何批量爬取等等。

总结

数据对于分析师,就好比食材对于厨师,只有上好的食材,做出来的食物才甜美可口。那如何获得上等的数据呢,可以从开源数据下载,可以用商用的采集器比如八爪鱼采集,当然也可以自己动手设计爬虫采集。对于每一种途径,本文都提供了相应的渠道供朋友们使用。

对于新入门的朋友们,需要注重于对数据分析逻辑的理解和常用技巧的掌握。朋友们在熟悉这些技巧之后,也可以从国内外(优先推荐国内,因为更加贴近生活)的开源数据库中,下载数据进行数据清洗和可视化,增加实战经验。

爬虫则常常应用于于深度定制的专题化数据需求,朋友们在兴趣和经验的基础上,可以多做一些有益的尝试。

AI悦创·创造不同!
AI悦创 » 数据准备篇:没有数据怎么办,当然自己爬喽

Leave a Reply