Python 网页投票信息抓取

最近学习python,为了巩固一下学过的知识,花了半天(主要还是因为自己正则表达式不熟)写了个小脚本来抓取一个网站上的投票信息,排名后进行输出。

抓取的网站网址是http://www.mudidi.net/topic-yinghuhuodong.html。我先在网站首页点了个查看源码,发现并没有下面的投票部分信息,颇为不解,咨询了一个PHP大牛同学,原来那部分是一个嵌套页面,有另外一个地址http://www.mudidi.net//toupiao/vote3.asp?id=2,真是才疏学浅,自惭形愧啊。

找到真实地址后,就可以提取页面信息了:

1 # 获取页面数据
2 def getUrlRespHtml():
3     url = 'http://www.mudidi.net//toupiao/vote3.asp?id=2'
4     req = urllib2.Request(url)
5     resp = urllib2.urlopen(req)
6     respHtml = resp.read()
7     # 由于存在汉字,将页面转码成utf-8
8     respHtml = respHtml.decode('gbk').encode('utf-8')
9     return respHtml

这里写了个函数,调用了urllib2这个库。最开始版本并没有转码这一步,但是结果会造成提取出的汉字都是乱码,查了好多资料,才知道需要转码,再次感叹才疏学浅,对网络编程真是没什么经验。

提取出网页信息后,就需要对信息进行处理。由于网页信息中我们需要的信息格式都是相同的,如下所示:

 1 <div class="tp">
 2 <form action="vote_pass.asp" method="post" name="add">
 3   <div align="center" style="white-space:now=rap; overflow:hidden;width:200px;font-size:13px;margin-top:0px;margin-bottom:10px;">安康山水 美哉瀛湖
 4       <label>
 5       <input type="hidden" name="id"  value="1"/>
 6       </label>
 7     </div>
 8     <div align="center" style="margin-top:0px;margin-bottom:10px;">NO1 作者:飞扬古</div>
 9     <div align="center" style="margin-top:0px;color:#990000; font-weight:bold; font-size:14px; font-family:'Times New Roman', Times, serif;margin-top:0px;margin-bottom:7px;">票数:23</div>
10       <div align="center" style="">       
11        <input type="image" name="button" src="vote1.gif" />    
12         </div>
13         </form>
14 </div>

则需要写正则表达式匹配这一段落。我们需要的信息包括标语(如上所示的“安康山水 美哉瀛湖”)、ID(如上所示的NO1)、作者、票数。

我首先想到的是findall()函数,可以得到符合条件的列表,而且可以直接提取出我们需要的信息。可是无论我怎么写正则表达式都无法得到想要的结果。然后我就写了这么个正则表达式:“<form.*?</form>”,然后调用findall()函数,直接把所有的<form></form>段匹配了出来,得到了完整的格式(以上面的HTML代码为例):

“<form action="vote_pass.asp" method="post" name="add">\r\n  <div align="center" style="white-space:now=rap; overflow:hidden;width:200px;font-size:13px;margin-top:0px;margin-bottom:10px;">安康山水 美哉瀛湖\r\n      <label>\r\n      <input type="hidden" name="id"  value="1"/>\r\n      </label>\r\n    </div>\r\n\t<div align="center" style="margin-top:0px;margin-bottom:10px;">NO1 作者:飞扬古</div>\r\n\t<div align="center" style="margin-top:0px;color:#990000; font-weight:bold; font-size:14px; font-family:\'Times New Roman\', Times, serif;margin-top:0px;margin-bottom:7px;">票数:23</div>”。

将这一段改成正则表达式,我直接把我想要提取的地方(红色部分)改为(.*),就可以得到想要的信息:

“<form action="vote_pass.asp" method="post" name="add">\r\n  <div align="center" style="white-space:now=rap; overflow:hidden;width:200px;font-size:13px;margin-top:0px;margin-bottom:10px;">(.*)\r\n      <label>\r\n      <input type="hidden" name="id"  value="(.*)"/>\r\n      </label>\r\n    </div>\r\n\t<div align="center" style="margin-top:0px;margin-bottom:10px;">NO(.*) 作者:(.*)</div>\r\n\t<div align="center" style="margin-top:0px;color:#990000; font-weight:bold; font-size:14px; font-family:\'Times New Roman\', Times, serif;margin-top:0px;margin-bottom:7px;">票数:(.*)</div>”。

将这个正则表达式调用re.compile()函数编译,然后调用re.findall()函数即可得到符合该格式的列表。代码如下:

 1 def getVoteLists(html):
 2     # 编译正则表达式模式
 3     pattern = re.compile('<form action="vote_pass.asp" method="post" name="add">\r\n  <div align="center" style="white-space:now=rap; overflow:hidden;width:200px;font-size:13px;margin-top:0px;margin-bottom:10px;">(.*)\r\n      <label>\r\n      <input type="hidden" name="id"  value="(.*)"/>\r\n      </label>\r\n    </div>\r\n\t<div align="center" style="margin-top:0px;margin-bottom:10px;">NO(.*) 作者:(.*)</div>\r\n\t<div align="center" style="margin-top:0px;color:#990000; font-weight:bold; font-size:14px; font-family:\'Times New Roman\', Times, serif;margin-top:0px;margin-bottom:7px;">票数:(.*)</div>')
 4     matchlist = re.findall(pattern, html)
 5 
 6     vlist = []
 7     # 将用户ID和票数由str型转换成int型,由于findall()函数得到的列表元素是元组不可改,因此需要转换成可修改的列表
 8     for item in matchlist:
 9         itemlist = list(item)
10         itemlist[1] = int(itemlist[1])
11         itemlist[4] = int(itemlist[4])
12         vlist.append(itemlist)
13     # 根据票数进行排序
14     return sorted(vlist, key=lambda x:x[4], reverse=True)

 

使用re.findall()函数得到一个列表,列表中每个元素是一个元组,元组中包含标语、两个ID(一个HTML代码段中有两个ID变化)、作者、票数。我们将得到的结果根据票数进行排序。由于这些结果都是str类型,无法排序,需要将str转换成int类型,而元组中元素是不可改的,因此在函数中重新生成了个列表,将原列表中的元组改为列表,再对列表中的元素进行类型转换。转换完成后,调用sorted()函数根据票数进行排序。

最后,将结果输出前16项(随意定)。完整代码如下:

 1 #!/usr/bin/env python
 2 # -*- coding: UTF-8 -*-
 3 
 4 import urllib2
 5 import re
 6 
 7 # 获取页面数据
 8 def getUrlRespHtml():
 9     url = 'http://www.mudidi.net//toupiao/vote3.asp?id=2'
10     req = urllib2.Request(url)
11     resp = urllib2.urlopen(req)
12     respHtml = resp.read()
13     # 由于存在汉字,将页面转码成utf-8
14     respHtml = respHtml.decode('gbk').encode('utf-8')
15     return respHtml
16 
17 def getVoteLists(html):
18     # 编译正则表达式模式
19     pattern = re.compile('<form action="vote_pass.asp" method="post" name="add">\r\n  <div align="center" style="white-space:now=rap; overflow:hidden;width:200px;font-size:13px;margin-top:0px;margin-bottom:10px;">(.*)\r\n      <label>\r\n      <input type="hidden" name="id"  value="(.*)"/>\r\n      </label>\r\n    </div>\r\n\t<div align="center" style="margin-top:0px;margin-bottom:10px;">NO(.*) 作者:(.*)</div>\r\n\t<div align="center" style="margin-top:0px;color:#990000; font-weight:bold; font-size:14px; font-family:\'Times New Roman\', Times, serif;margin-top:0px;margin-bottom:7px;">票数:(.*)</div>')
20     matchlist = re.findall(pattern, html)
21 
22     vlist = []
23     # 将用户ID和票数由str型转换成int型,由于findall()函数得到的列表元素是元组不可改,因此需要转换成可修改的列表
24     for item in matchlist:
25         itemlist = list(item)
26         itemlist[1] = int(itemlist[1])
27         itemlist[4] = int(itemlist[4])
28         vlist.append(itemlist)
29     # 根据票数进行排序
30     return sorted(vlist, key=lambda x:x[4], reverse=True)
31     
32 def main():
33     print 'loading...'
34     html = getUrlRespHtml()
35     mList = getVoteLists(html)
36 
37     # 显示前16位
38     print 'Rank\tID\tVoteNums\tAuthor\t\tContent'
39     print '-' * 60
40     for i in range(16):
41         print '%d\t%d\t%d\t\t%s\t\t%s' % (i+1, mList[i][1], mList[i][4], mList[i][3], mList[i][0])
42     
43 
44 if __name__ == '__main__':
45     main()

这是对前一段时间学习Python的一个巩固练习。有什么更好更高效的方法欢迎留言讨论。

posted @ 2013-07-15 15:31  Kill Console  阅读(1324)  评论(0)    收藏  举报