实时抓取网页数据(如何把网站提供的网页数据转换成格式化的数据(图))

优采云 发布时间: 2022-03-08 16:07

  实时抓取网页数据(如何把网站提供的网页数据转换成格式化的数据(图))

  2022全球C++与系统软件技术大会| 3月11-12日上海点击查看详情>>>

  

  背景网页抓取

  大数据时代,一切都要用数据说话,而大数据处理的过程一般需要经过以下几个步骤

  首先要做的是获取数据并提取有效数据,为下一步分析做准备。

  有各种数据来源。我以为我是个足球爱好者,世界杯快到了,所以我想提取欧洲联赛的数据进行分析。很多网站都提供了详细的足球数据,比如:

  这些网站提供了详细的足球数据,但是为了进一步分析,我们希望数据以格式化的形式存储,那么如何将这些网站提供的网页数据转换成格式化数据呢?? 这使用了网页抓取技术。简单来说,Web Scraping就是从网站中提取信息,通常使用程序来模拟人们浏览网页的过程,发送http请求,从http响应中获取结果。

  网页抓取注意事项

  在抓取数据之前,请注意以下几点:

  Python Web Scraping 相关库

  Python 提供了一个非常方便的 Web Scraping 基础,具有许多支持库。这是一个小选择

  当然,您不必使用 Python,也不必编写自己的代码。建议关注import.io

  网页抓取代码

  接下来,我们将一步步使用Python从腾讯体育抓取2013/14赛季欧洲联赛的数据。

  首先安装 Beautifulsoup

  pip install beautifulsoup4

  让我们从玩家的数据开始。

  对玩家数据的网络请求是,返回的内容如下图所示:

  

  web服务有两个参数,lega表示是哪个联赛,pn表示分页数。

  首先,我们来做一些初始化准备

  from urllib2 import urlopen

import urlparse

import bs4

BASE_URL = "http://soccerdata.sports.qq.com"

PLAYER_LIST_QUERY = "/playerSearch.aspx?lega=%s&pn=%d"

league = ['epl','seri','bund','liga','fran','scot','holl','belg']

page_number_limit = 100

player_fields = ['league_cn','img','name_cn','name','team','age','position_cn','nation','birth','query','id','teamid','league']

  urlopen、urlparse、bs4 是我们将使用的 Python 库。

  BASE_URL、PLAYER_LIST_QUERY、league、page_number_limit 和 player_fields 是我们将使用的一些常量。

  下面是抓取玩家数据的具体代码:

  def get_players(baseurl):

    html = urlopen(baseurl).read()

    soup = bs4.BeautifulSoup(html, "lxml")

    players = [ dd for dd in soup.select('.searchResult tr') if dd.contents[1].name != 'th']

    result = []

    for player in players:

        record = []

        link = ''

        query = []

        for item in player.contents:

            if type(item) is bs4.element.Tag:

                if not item.string and item.img:

                    record.append(item.img['src'])

                else :

                    record.append(item.string and item.string.strip() or 'na')

                try:

                    o = urlparse.urlparse(item.a['href']).query

                    if len(link) == 0:

                        link = o

                        query = dict([(k,v[0]) for k,v in urlparse.parse_qs(o).items()])

                except:

                    pass

             

        if len(record) != 10:

            for i in range(0, 10 - len(record)):

                record.append('na')

        record.append(unicode(link,'utf-8'))

        record.append(unicode(query["id"],'utf-8'))

        record.append(unicode(query["teamid"],'utf-8'))

        record.append(unicode(query["lega"],'utf-8'))

        result.append(record)

    return result

    

result = []

for url in [ BASE_URL + PLAYER_LIST_QUERY % (l,n) for l in league for n in range(page_number_limit) ]:

    result = result +  get_players(url)

  我们来看看抓取玩家数据的详细过程:

  首先,我们定义一个 get_players 方法,该方法返回请求页面上所有玩家的数据。为了得到所有的数据,我们通过了一个for循环,因为我们要循环遍历每个联赛,每个联赛有多个页面。一般需要双循环:

  for i in league:

    for j in range(0, 100):

        url = BASE_URL + PLAYER_LIST_QUERY % (l,n)

        ## send request to url and do scraping

  Python 的列表推导可以通过构建列表轻松降低循环的级别。

  此外,Python 有一个非常方便的合并连续列表的语法:list = list1 + list2

  好,我们来看看如何使用BeautifulSoup来抓取网页中我们需要的内容。

  首先调用urlopen读取对应url的内容,一般是html,用html构造一个beautifulsoup对象。

  beautifulsoup 对象支持许多搜索功能,以及类似 css 的选择器。通常如果有一个 DOM 对象,我们使用下面的方式来查找它:

  obj = soup.find("xx","cc")

  另一种常用的方法是使用 CSS 选择器方法。在上面的代码中,我们选择了class=searchResult元素中的所有tr元素,过滤掉了th,也就是header元素。

  for dd in soup.select('.searchResult tr') if dd.contents[1].name != 'th'

  

  对于记录 tr 的每一行,都会生成一个玩家记录并将其存储在一个列表中。所以我们循环tr tr.contents 的内容来获取对应的字段内容。

  对于每个tr的内容,我们首先检查它的类型是否为Tag。Tag 类型有几种情况。一种是收录 img 的案例。我们需要取出玩家头像图片的URL。

  

  另一种是收录指向其他数据内容的链接

  

  所以这些不同的情况在代码中分别处理。

  对于一个Tag 对象,Tag.x 可以得到它的子对象,Tag['x'] 可以得到Tag 的属性值。

  所以使用 item.img['src'] 来获取 item 的子元素 img 的 src 属性。

  对于已经收录链接的情况,我们使用urlparse来获取查询url中的参数。在这里,我们利用字典理解将查询参数放入字典,然后添加到列表中。

  dict([(k,v[0]) for k,v in urlparse.parse_qs(o).items()])

  对于其他情况,我们使用 Python 的 and or 表达式来保证当 Tag 的内容为空时,我们写 'na',类似于三元运算符 X ? A : B 在 C/C++ 或 Java 中

  然后有一段代码判断当前记录的长度是否大于10,如果不大于10则用空值填充,以避免出现一些不一致的情况。

  if len(record) != 10:

    for i in range(0, 10 - len(record)):

        record.append('na')

  最后,我们在查询中添加一些相关参数,比如球员的id、球队的id、联赛代码等到列表中。

  record.append(unicode(link,'utf-8'))

record.append(unicode(query["id"],'utf-8'))

record.append(unicode(query["teamid"],'utf-8'))

record.append(unicode(query["lega"],'utf-8'))

  最后,我们把这个页面上所有玩家的列表放到一个列表中,然后返回。

  好的,现在我们有了一个收录所有玩家信息的列表,我们需要保存它以供进一步处理、分析。通常,csv 格式是一种常见的选择。

  import csv

def write_csv(filename, content, header = None): 

    file = open(filename, "wb")

    file.write('\xEF\xBB\xBF')

    writer = csv.writer(file, delimiter=',')

    if header:

        writer.writerow(header)

    for row in content:

        encoderow = [dd.encode('utf8') for dd in row]

        writer.writerow(encoderow)

write_csv('players.csv',result,player_fields)

  这里需要注意的是编码的问题。因为我们使用的是utf-8编码方式,所以在csv的文件头中,我们需要写\xEF\xBB\xBF,详见这篇文章文章

  好了,现在大功告成,捕获的csv如下:

  

  因为之前我们也抓取了本赛季球员的比赛详情,所以我们可以进一步抓取所有球员每场比赛的记录

  

  抓取的代码如下

  def get_player_match(url):

    html = urlopen(url).read()

    soup = bs4.BeautifulSoup(html, "lxml")

    matches = [ dd for dd in soup.select('.shtdm tr') if dd.contents[1].name != 'th']

    records = []

    for item in [ dd for dd in matches if len(dd.contents) > 11]: ## filter out the personal part

        record = []

        for match in [ dd for dd in item.contents if type(dd) is bs4.element.Tag]:

            if match.string:

                record.append(match.string)

            else:

                for d in [ dd for dd in match.contents if type(dd) is bs4.element.Tag]:

                    query = dict([(k,v[0]) for k,v in urlparse.parse_qs(d['href']).items()])

                    record.append('teamid' in query and query['teamid'] or query['id'])   

                    record.append(d.string and d.string or 'na')                    

        records.append(record)

    return records[1:]  ##remove the first record as the header

def get_players_match(playerlist, baseurl = BASE_URL + '/player.aspx?'):

    result = []

    for item in playerlist:

        url =  baseurl + item[10]

        print url

        result = result + get_player_match(url)

    return result

match_fields = ['date_cn','homeid','homename_cn','matchid','score','awayid','awayname_cn','league_cn','firstteam','playtime','goal','assist','shoot','run','corner','offside','foul','violation','yellowcard','redcard','save']    

write_csv('m.csv',get_players_match(result),match_fields)

  爬取过程与之前类似。

  接下来做什么

  既然我们已经有了详细的欧联杯数据,接下来我们应该怎么做呢?我建议您将数据导入 BI 工具以进行进一步分析。有两个更好的选择:

  Tableau 在数据可视化领域是无与伦比的。Tableau Public 完全免费。它使用数据可视化来驱动数据探索和分析,具有非常好的用户体验。

  Splunk 提供了一个大数据平台,主要针对机器数据。支持每天免费导入500M数据,个人学习应该够用了。

  当然你也可以使用 Excel。另外,如果大家有什么好的免费数据分析平台,欢迎交流。

0 个评论

要回复文章请先登录注册


官方客服QQ群

微信人工客服

QQ人工客服


线