PYTHON 实现 NBA 赛程查询工具(二)—— 网络爬虫

前言:

第一篇博客,记录一下最近的一点点小成果。

一切的学习都从兴趣开始。最近忽然想学习一下 pyqt 和 python 的网络爬虫知识,于是就自己找了一个课题做了起来。因为我正好是个 NBA 球迷,就想到了通过网络爬虫来抓取比赛结果,方便本地进行查找的项目。

这个项目总共分为三步:

1. 界面制作

选择对应的球队,显示球队图标和比赛结果

2. 网络爬虫

访问特定网页,查找赛季至今的比赛结果信息,并保存到本地作为待查找的文件

3. 工具打包

将上述两部分联调,并生成exe 工具直接调用

我预备从以上三个部分,分别记录该查询工具的实现过程。

 

网络爬虫:

说到python学习,爬虫是一个避不开的话题。这个项目要能实时展示截止到当前比赛日的比赛结果,而不是本地存了多少比赛,就只能查这么多的比赛。这就需要通过爬虫,爬取特定网页上的比赛信息。

 

1. 查看源代码:

先以某个特定球队开始分析。由于我主队是太阳,因此选用太阳作为分析的示例

选用的网页是虎扑,链接如下:

https://nba.hupu.com/schedule/suns

 

要进行网络爬虫,需要先明确这个网页是用什么格式写成的。

以上述网页为例,右键点击查看源代码,可以得到以下界面,如图1所示:


图1 赛程网页源代码

从源码中可以看到,每一场比赛的格式均如下:

<tr class="left">
<td class="left">
<a href="https://nba.hupu.com/teams/suns" target="_blank" style="font-weight:bold;">太阳</a> vs <a href="https://nba.hupu.com/teams/blazers" target="_blank" >开拓者</a>
</td>
<td class="left">
114 - 112
</td>
<td class="left">
胜
</td>
<td class="left">2017-10-04 10:00:00</td>
<td>
<a target="_blank" href="https://nba.hupu.com/games/boxscore/154278">数据统计</a>   <a target="_blank" href="http://v.liangle.com/nba/v844972.html">比赛视频</a>
</td>
</tr>

2. 抓取源码中的信息:

对网页源代码做进一步的分析,可以发现每一场比赛的格式非常固定,均是以<tr class=”left”>开头,以</tr>结尾,且中间的格式也非常固定,因而想到用正则表达式去匹配网页内的信息,将匹配得到的信息,作为查询到的结果保存,就可以得到完整的赛果。

首先将网页内的源代码整个保存出来,使用如下代码即可:

    url = 'https://nba.hupu.com/schedule/suns'
    user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'
    headers = { 'User-Agent' : user_agent }
    request = urllib2.Request(url,headers = headers)
    response = urllib2.urlopen(request)
    content = response.read().decode('utf-8')

得到源码之后,将源码当做字符串来处理。需要用到正则表达式去匹配字符串。

正则表达式的规则就不详述了,主要是我自己也没弄清楚,对于这个项目来说,够用的正则表达式就行。

由于每一段格式一样,用正则表达式的方式匹配字符串:

*

匹配前面的子表达式任意次。例如,zo*能匹配“z”,也能匹配“zo”以及“zoo”*等价于o{0,}

+

匹配前面的子表达式一次或多次(大于等于1次)。例如,“zo+”能匹配“zo”以及“zoo”,但不能匹配“z”+等价于{1,}

?

当该字符紧跟在任何一个其他限制符(*,+,?{n}{n,}{n,m})后面时,匹配模式是非贪婪的。非贪婪模式尽可能少的匹配所搜索的字符串,而默认的贪婪模式则尽可能多的匹配所搜索的字符串。例如,对于字符串“oooo”“o+”将尽可能多的匹配“o”,得到结果[“oooo”],而“o+?”将尽可能少的匹配“o”,得到结果 ['o', 'o', 'o', 'o']

.

匹配除“\r\n”之外的任何单个字符。要匹配包括“\r\n”在内的任何字符,请使用像“[\s\S]”的模式。

(pattern)

匹配pattern并获取这一匹配。所获取的匹配可以从产生的Matches集合得到,在VBScript中使用SubMatches集合,在JScript中则使用$0…$9属性。要匹配圆括号字符,请使用“\(”“\)”


.*? 连用,就可以匹配任意长度的字符

用以下式子直接匹配整串包括【比赛双方,主客关系,比分,比赛时间】在内的内容

web_str = '<a href="http.*?target="_blank".*?>(.*?)</a>.*?<a href="http.*?target="_blank".*?>(.*?)</a>\s<\td>\s<td class="left">\s(.*?)&nbsp;-&nbsp;'#(.*?)\n</td>[\s\S]*?</td>[\s\S]*?<td class="left">(.*?)</td>'

但是这种匹配方式在实际应用中失败了,并没有根据这种方式匹配到实际想要的信息。哪怕可以在网页端用正则表达式匹配助手匹配到了正确的信息,但是程序里也无法识别。至今不知道是为什么。有人知道为什么,欢迎在评论中指出。

在经过多次尝试之后,放弃了直接匹配。采用更简练的方式去匹配,如下所示:

web_str = '<tr class="left">'+'.*?<td class="left">(.*?)</td>'*4 + '.*?</tr>'


在匹配到较长的字符串之后,再做相应的修改,再次提取想要的信息。等于是将原先的一段式正则匹配,改为了两段式。总之最后解决问题就好,但是没有想通第一步为什么没能匹配成功,确实很不甘心。


3. 保存内容

 用()将最后需要的内容取出,并保存即可。

由于这样匹配之后,会出现很多的脏信息,因此人为设定了开始条件,直到搜索到u'2017至2018赛季',之后的信息单独保存,并从这段信息中去做正则匹配。本例中恰好没有尾部的垃圾信息需要处理,如果有需要的话,增加一条去除尾部垃圾信息的语句即可。

同时这样搜索,会把季前赛的比赛也一并保存起来,实际上并不想搜索季前赛的结果,因此将时间也做了筛选,只有当比赛的开始时间晚于“2017年10月18日”,才记录在csv文件中。

 

另外这就是个爬虫初步入门,我还没学会怎么从某网页中抓取别的链接并进去的方法。因此抓取每支球队比赛的方式,只是遍历。。确实很low,等学会了高级方法之后,把这一点改善了。


相关链接:

PYTHON 实现 NBA 赛程查询工具(一)—— pyqt界面

PYTHON 实现 NBA 赛程查询工具(三)—— 工具打包



猜你喜欢

转载自blog.csdn.net/panfengzjz/article/details/78945466