python网络爬虫之农大绩点计算器

本文记录了作者学习Python过程中制作的一个网络爬虫,用于抓取并计算中国农业大学的绩点。通过解析网页,使用正则表达式进行数据抽取,作者体验到正则表达式对爬虫效率的影响,并分享了使用Python2.7和Sublime编辑器的体验。参考了廖雪峰的Python教程及汪海的实验室系列文章。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近在家无聊,正好在网上看到一份不错的python教程,于是就学起了python。python是动态语言且具有函数式编程的特点,相比C/C++、java这类静态语言,有很多不同并且很有意思的地方。在学习到教程的常用内建模块xml部分时,老师留下一份作业:


练习一下解析Yahoo的XML格式的天气预报,获取当天和最近几天的天气:

http://weather.yahooapis.com/forecastrss?u=c&w=2151330


这不就是类似网络爬虫的意思吗,然后我就google it,发现很多网络爬虫的教程,都非常有意思,其中比较好的一个,也是我参考的一个:点这里。在里面初步学习了几篇教程后,就迫不及待上手试试,参考博主博文一个爬虫的诞生全过程(以山东大学绩点运算为例),自己做了一个农大的爬虫程序,并且计算出了自己的GPA,下面是我的代码:

#!/usr/bin/env python3  
# -*- coding: utf-8 -*-  
import string  
import urllib  
import urllib2  
import cookielib  
import re  
import time  
  
class CAU_GPA_Spider:  
    #申明相关属性  
    def __init__(self):  
        self.loginUrl = 'http://urpjw.cau.edu.cn/loginAction.do'  
        self.resultUrl = 'http://urpjw.cau.edu.cn/gradeLnAllAction.do?type=ln&oper=sxinfo&lnsxdm=001'  
        self.cookieJar = cookielib.CookieJar()  
        self.postdata = urllib.urlencode({  
            'zjh':'1211250521',  
            'mm':'xxxxxxxx'  
            }) #密码我在这里就不写出来了,O(∩_∩)O哈哈~  
        self.GPA = None  
        self.subjects = [] # 储存科目  
        self.weights = [] # 储存学分  
        self.points = [] # 储存分数  
        self.opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(self.cookieJar))  
  
    def cau_init(self):  
        #初始化链接并获取cookie  
        myRequest = urllib2.Request(url = self.loginUrl, data = self.postdata) # 自定义请求  
        result = self.opener.open(myRequest) # 访问登录页面,获取必要cookie  
        result = self.opener.open(self.resultUrl) # 访问登录成绩页面,获取必要数据  
        self.deal_data(result.read())  
        # self.print_data(self.subjects)  
        # self.print_data(self.weights)  
        # self.print_data(self.points)  
        self.calculate_date()  
  
    def deal_data(self,myPage):  
        myItems = re.findall('<tr class="odd" onMouseOut="this.className=\'even\';" onMouseOver="this.className=\'evenfocus\';">.*?<td align="center".*?<td align="center".*?<td align="center">\s+(.*?)\s+</td>.*?<td align="center".*?<td align="center".*?>.*?(\d\.\d|\d).*?</td>.*?<td align="center".*?<td align="center".*?>.*?<p.*?>(\d\d\.\d) </P>.*?</td>.*?</tr>',myPage,re.S)  
        for item in myItems:  
            self.subjects.append(item[0])  
            self.weights.append(item[1])  
            self.points.append(item[2])  
  
    def print_data(self,items):  
        for item in items:  
            print item  
  
    def get_level(self, point):  
        point = string.atof(point)  
        if point >= 90 and point <= 100:  
            return 4.0  
        elif point >=85 and point <= 89:  
            return 3.7  
        elif point >=82 and point <= 84:  
            return 3.3  
        elif point >=78 and point <= 81:  
            return 3.0  
        elif point >=75 and point <= 77:  
            return 2.7  
        elif point >=72 and point <= 74:  
            return 2.3  
        elif point >=68 and point <= 71:  
            return 2.0  
        elif point >=64 and point <= 67:  
            return 1.5  
        elif point >=60 and point <= 63:  
            return 1.0  
        else:  
            return 0  
  
    def calculate_date(self):  
        points = 0.0  
        weights = 0.0  
        for i in range(len(self.points)):  
            pattern = re.compile('\d\d\.\d')  
            match = pattern.match(self.points[i])  
            if match:  
                points += self.get_level(self.points[i]) * string.atof(self.weights[i])  
                weights += string.atof(self.weights[i])  
        if weights != 0:  
            self.GPA = points/weights  
  
start = time.time()  
mySpider = CAU_GPA_Spider()  
mySpider.cau_init()  
end = time.time()  
print 'your GPA:',mySpider.GPA  
print 'run time:', end-start, 's'  

程序运行截图


其中网络爬虫程序中的数据抽取部分,用到了正则表达式,对参考资料中的

myItems = re.findall('<TR>.*?<p.*?<p.*?<p.*?<p.*?<p.*?>(.*?)</p>.*?<p.*?<p.*?>(.*?)</p>.*?</TR>',myPage,re.S)     #获取到学分    
根据从农大教务处网页爬下来的网页数据,对正则表达式进行修改,最开始是改为

myItems = re.findall('<tr>.*?<td.*?<td.*?<td.*?<td.*?<td.*?>.*?(\d\.\d|\d).*?</td>.*?<td.*?<td.*?>.*?<p.*?>(\d\d\.\d) </P>.*?</td>.*?</tr>',myPage,re.S) #获取到学分  
后来在运行时,光标一直闪烁,没有输出,我以为程序死循环了,后来一直查程序那里错了,结果在几分钟之后突然出数据了,统计一下程序运行时间:210秒+,这么慢的效率怎么能行。把网页数据保存为本地文件,然后单独写了一个.py文件,用正则表达式抽取数据,发现程序慢的原因是在网页数据的后半部分,也就是接近页脚那个地方,和正则表达式匹配度很高,估计程序就是卡在正则表达式在页脚那部分的计算了,唯一的办法只有修改正则表达式,根据网页源文件的内容进行分析,最后的正则表达式是:

myItems = re.findall('<tr class="odd" onMouseOut="this.className=\'even\';" onMouseOver="this.className=\'evenfocus\';">.*?<td align="center".*?<td align="center".*?<td align="center">\s+(.*?)\s+</td>.*?<td align="center".*?<td align="center".*?>.*?(\d\.\d|\d).*?</td>.*?<td align="center".*?<td align="center".*?>.*?<p.*?>(\d\d\.\d) </P>.*?</td>.*?</tr>',myPage,re.S) #获取到学分  
这样修改之后,程序运行时间是run time: 0.768000125885s


正则表达式稍微知道一点,但是具体实现细节不太清楚,经过这次的爬虫程序,发现正则表达式的内容对数据抽取效率有很大影响,同样能抽取出数据的正则表达式,引起的效率可能是几千倍的差距。关键还是要好好分析要抽取出数据的源文件,找出要抽取部分和其他部分的区别,写出的正则表达式要尽量排除源文件中除要抽取数据之外的其它干扰部分。


另外,我的爬虫程序运行环境是python2.7.x,编辑器sublime,pycharm也是一个不错的编辑器,前几天刚下载但是还没有用习惯。sublime是用的比较多的一个编辑器,界面很漂亮。


参考资料

[1] Python教程 - 廖雪峰的官方网站(http://www.liaoxuefeng.com/wiki/001374738125095c955c1e6d8bb493182103fac9270762a000)

[2] [Python]网络爬虫(十):一个爬虫的诞生全过程(以山东大学绩点运算为例) - 汪海的实验室 - 博客频道 - CSDN.NET (http://blog.csdn.net/pleasecallmewhy/article/details/9305229)

[3] [Python]网络爬虫(七):Python中的正则表达式教程 - 汪海的实验室 - 博客频道 - CSDN.NET

(http://blog.csdn.net/pleasecallmewhy/article/details/8929576)



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值