python基础入门之简单爬虫编写

学习python不到一个星期,看的东西可能连皮毛也算不上,只是简单的看了几篇快速入门的技术博客,随手敲了敲代码,这也能算是入门吗 = =

由于之前的研究方向和这些没有太多交集,所以总觉得爬虫之类的东西很神奇,恰巧前些时间,学校里的一位老师“不小心” 的泄露了所有同学的“学号”+“身份证号”的组合,学生群里刚刚有人说这样不好,但是我已经知道了该怎样以这个为基础用python做个小玩具了。

这里主要完成了一个自动登录教务系统(哪个学校就不说了),抓取并下载考试成绩的爬虫程序,功能实现后代码没有什么优化,只是实现了想要的功能。最后从抓取的结果来看,自己成绩真的不怎么样,哎,说多了都是泪~~

1.环境&开发工具

python:强类型,隐式类型,动态性,大小写敏感,面向对象

版本:python2.7,安装过后需要配置环境变量path(类似java),此处不赘述

开发工具:从ST3又换到了IDLE。ST3的运行是Ctrl+B,停止运行Esc即可,但不知道为什么不能输入,所以换到了IDLE。个人还是倾向于ST。

2.语法/数据类型

单行注释:#

多行注释:多行#

数据类型:tuple,list,dictionary,代表符号依次为"()","[]","{}",前两个类似数组,区别是可变与不可变的关系,个人感觉用list的多些,一般情况下数组的返回类型也都是list,dictionary类似于hashmap,存储的是键值对。特别的是python的数据类型没有规定一定要使用某一种数据类型,也并没有固定的数据类型,所以以上几种数据类型中的每一项都可以是任意的数据类型,这种做法极大提高了编程的自由度。当然,二维数组什么的就可以用列表的列表来模拟,访问的时候也可以用"[][]"来访问,以上几种数据结构的访问也都是用"[]"来访问,只不过里面写的是数组的索引还是key的区别了。

3.文件IO

个人感觉python里的IO很简洁,在爬虫里主要用作:

①批量读入学生的学号和身份证号(账号和密码)

②批量向文本文件写入处理好的学生信息和成绩


写文件

f = file('src', 'w')
<pre>f.write('hello world')
 
其中,'w'参数设定为写入,每次会将原有存在内容覆盖,追加写入可以将参数变为'a',写入后不要忘了flush和close,可以用try&finally实现。对于写文件简单写这么多,其实感觉知识还是很多的,以后再做仔细研究吧~ 

读文件

f = open('stu.txt')
while True:
    line = f.readline()
    if(line):
        #code...
这个也不多说,其实网上有很多资源。

提一下,我在写的时候,读取的每一行多了个换行符,还需要将这个换行去掉。

4.输入和输出

程序最后没有用到输入,主要用于控制台监测程序执行状况,也可以将写入文本内容输出。

输入:有以下两种方法,接受的分别是数字型的变量和字符串型的变量,可以用type(val)来进行查看,这里要注意,对于第一种输入,如果输入的是非数字,会报变量名找不到的错。参数是提示输入的内容。

numVal = input('input a num:')
strVal = raw_input('input a str:')
输出:简单粗暴的一个print,可以不加括号后面直接跟变量,变量后加','表示不换行,否则就是换行输出,这一点的设计非常好用,没有了那么多繁琐的输出方式。

print(str1,str2)

5.OO

这个先不讨论,毕竟自己最后也没用到,python还是自由一些,小程序没必要一定要OO,但是OO也是一种编程习惯。

6.函数

使用def对函数进行声明,可以有返回值,也可以没有,可以返回元组,有必选参数和可选参数,可选参数必须赋默认值。

def funcName(para1, para2):
    #code...
    #return...
在函数中使用全局变量(虽然不建议使用全局变量)的话,就要注意一点:

由于python的变量没有声明,所以是系统会把赋值的变量认为是本地变量,因此在函数中调用函数外部的全局变量如果直接写变量名,会变成局部变量。

若要访问全局变量,可以在函数中对全局变量重复使用global进行声明。

7.正则

这个对于处理下载的HTML文本是必须的,包括匹配并处理HTML文本,获取必要信息

由于之前学过一点,所以就直接拿来主义了

首先要"import re",才能使用正则的内置对象,主要就是以下两部,第一步建立匹配对象,第二部进行匹配以及对匹配内容进行操作。

p = re.compile(r'<[^>]+?>')    
name = p.sub("", name)

 
方法有很多种,这里只用了sub(替换/删除)和findall(查找并返回元组),具体还有很多,现用现查也来得及,总之是可以满足任何需求的。 

这里提个技巧,去除文本中所有的空格,换行,回车。其中join和split是互逆的两个方法。

right = opener.open('http://e.xxx.edu.cn/xxx/ax/ax').read()
squeezed_right = "".join(right.split()))

总之,这个现用现学完全来得及。

8.异常处理

在不断的登录过程中,总会有失败的时候,失败的时候程序会报错,导致程序终止,这样与我们获取所有人的成绩的需求是不符的,因此使用了几层try except来预防同一个学生账号多次连接失败的情况,如果一个学生连接失败的概率是p,那么写n个try except的情况下,失败的概率会被降到p^(n+1),在最后的测试中没有出现问题,网上看到可以用sleep的方式来延迟程序登录的频率,也是一种好方法。但是后来又换了一个时间测试了一次,就比较顺利,这个也许是和网络环境也有一定的关系。

其他异常处理见网上各种资源。

9.爬虫入门

这个觉得也都是在用python的库,其实更多的东西都是靠知识的积累和细心。第一次写这类的东西,感觉新鲜感还是挺足的。

主要是下载页面,解析页面文本

代码什么的,见最后吧~

10.小细节

浏览器调试很重要,很多东西都是靠F12和自己的观察来完成,做登录的时候要看浏览器和服务端都发送了哪些信息,在chrome里,依次是F12→Network,在这里选中想要的http请求,查看headers就可以了。一般找到登录请求,就可以将登录需要的字段找到。

爬取中会遇到字符编码的问题,如错误“UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-2: ordinal not in range(128)”,这时候网上通用的三段式做法如下:

import sys
reload(sys)
sys.setdefaultencoding('utf-8')
但修改后会发现,虽然不报错,但是程序的print,input等都不能用,这是因为重置sys后,输入输出都没有了定义,解决方法如下:

import sys
stdout = sys.stdout
stderr = sys.stderr
reload(sys)
sys.stdout = stdout
sys.stderr = stderr
sys.setdefaultencoding('utf-8')

11.成果

由于涉及到一点隐私,就不放太多的了,把名字也抹去了


12.结语

暑假期间,刚好打算学学这门语言,学习的过程还是挺有意思的,感觉学习的过程中还是需要有实践,在学习4天后写了这么个东西,大概有不到一半的同学没有修改密码,所以就获取到了同学们的成绩。其实,不如写点别的好玩的东西了,因为最后发现,除了有挂科的同学,我的成绩基本垫底,而且很少有挂科的同学 = =||,唉,成绩单不好看,真的不怪我,已经很努力了,好吧,就从其他地方弥补吧,还有一年,要加油了。

这也是CSDN的第一篇博客,之前的博客都是写在本机word里的,今天想想这样做毕竟是不好。至于这样做为什么不好,是有多方面原因的。这是这几天的学习和心得,以后有东西还是及时放上来,东西多了也就不想网上放了。

13.代码

初学,代码很丑,仅仅是实现了功能

# -*- coding: utf-8 -*-
import urllib  
import urllib2
import cookielib
import traceback
import re
import sys
import time
stdout = sys.stdout
stderr = sys.stderr
reload(sys)
sys.stdout = stdout
sys.stderr = stderr
sys.setdefaultencoding('utf-8')   

cnt = 0
tot = 0

def getInfo(uid, psw):
    cookie = cookielib.CookieJar()  
    opener = urllib2.build_opener(urllib2.HTTPCookieProcessor(cookie))
    
    #伪装成浏览器
    headers = {  
        'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.125 Safari/537.36',  
        'Host':'e.tju.edu.cn',  
        'Accept':'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',  
        'Referer':'http://e.tju.edu.cn/stuslls/achi/achi',  
        'Cookie':'',  
        'Connection':'keep=alive'  
    }
    
    #需要POST的数据#
    postdata=urllib.urlencode({  
        'loginBean.username':uid,  
        'loginBean.password':psw
    })
    
    #自定义请求#
    req = urllib2.Request(  
        url = 'http://e.tju.edu.cn/stuslls/login/login!login',  
        data = postdata,
        headers = headers
    )

    #访问该链接#
    result = opener.open(req)

    top = opener.open('http://e.tju.edu.cn/stuslls/main/Top.jsp').read()
    name_pattern = re.compile(r'<b>.+</b>')

    #登录成功(该学生没有修改密码)
    if len(name_pattern.findall(top))!=0:
        global cnt
        cnt += 1
        name = name_pattern.findall(top)[0].decode("utf-8")
        
        p = re.compile(r'<[^>]+>')    
        name = p.sub("", name)
        print(name)
        writeStr("result.txt", 'a', name)

        right = opener.open('http://e.tju.edu.cn/stuslls/achi/achi').read()
        scoreline_pattern = re.compile(r'<trbgcolor="#FFFFFF".+?</tr>')
        scorelines = scoreline_pattern.findall("".join(right.split()))

        for scoreline in scorelines:
            td_pattern = re.compile(r'<td.+?</td>')
            tds = td_pattern.findall(scoreline)
            str_scoreline = ''
            for td in tds:
                td = td.decode("utf-8")
                otd = p.sub(",",td)
                str_scoreline += otd  
            print(str_scoreline)
            writeStr("result.txt", 'a', str_scoreline.decode("utf-8"))


def writeStr(src, opType, data):
    try:
        f = file(src, opType)
        f.write(data.decode("utf-8") + '\n\r')
    finally:
        f.flush()
        f.close()

stuFile = open("stu.txt")
while True:
    line = stuFile.readline()
    tot +=1
    if(line):
        info = line.split("	")
        if(len(info)==2):
            
            stuID = info[0]
            stuPsw = info[1]
            rmn_pattern = re.compile(r'\n')
            rmr_pattern = re.compile(r'\r')
            stuPsw = rmn_pattern.sub('',stuPsw)
            print stuID
            print stuPsw
            try:
                print str(cnt),'/',str(tot)
                getInfo(stuID, stuPsw)
            except:
                time.sleep(2)
                print 'second time!!!!!!!!!!'
                getInfo(stuID, stuPsw)
    else:
        break



  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值