python爬取教务系统

其实,自己是一直打算爬取教务系统的,可是懒啊懒,懒啊懒,就一直懒到现在了。所以,寒假开始,痛改前非,重新做人,就稍微接触了一些python的知识,用来爬取每个学生都梦寐以求的教务系统。

前期准备

教务系统页面解析

首先,我们看看,教务系统页面长啥样?

这里,我们需要注意两点:

  1. 验证码的获取。
  2. 登陆时提交的信息。

验证码获取

这里,我们只需要进行抓包即可,这里我选择使用Fiddler进行抓包。首先打开Fiddler,然后刷新一下教务系统的界面即可。

我们在这里能够看到,获取验证码的URL是:http://210.42.121.241/servlet/GenImg

所以,我们就可以这样一步一步来获取我们需要的信息。

  1. 提交请求到:http://210.42.121.241/servlet/GenImg
  2. 下载验证码到本地,进行读取。(因为我也是刚接触python,所以这里就下载下来手动读取了,后面学习过程中,我会尝试用机器进行读取的)
  3. 输入验证码,提交到登陆请求,保存cookies。(这一步是很重要的)

登陆时提交信息

怎么取提交道路请求呢,我们继续来抓包。先清空Fiddler中的信息,然后在网页上输入学号,密码,验证码,点击登陆,就可以看到抓包信息了。

  1. http://210.42.121.241/servlet/Login是登陆的URL。

  2. 提交的请求包括三个参数:

    {
        id: 学号
        pwd: 密码
        xdvfb: 验证码
    }

这样,我们就可以模拟取提交请求,并登陆到我们的教务系统啦~

模拟登陆

好,那么我们现在就用python开始模拟登陆。

def get_cookie():
    # 验证码地址和登陆地址
    base_url = "http://210.42.121.241/servlet/GenImg"
    login_url = "http://210.42.121.241/servlet/Login"

    # 将cookie绑定到一个opener,cookie由cookielib自动管理
    cookie = cookielib.MozillaCookieJar("file.txt")
    handler = urllib2.HTTPCookieProcessor(cookie)
    opener = urllib2.build_opener(handler)

    # 用户名和密码
    username = "xxxxxxxxxxxxxxx"
    password = "xxxxxxxxxxxxxxx"

    # 用opener访问验证码地址,获取验证码
    picture = opener.open(base_url).read()
    # 保存验证码到本地
    local = open("image.jpg", "wb")
    local.write(picture)
    local.close()

    # 输入验证码,并构造表单
    secret_code = raw_input("请输入验证码:")
    data = {
        'id': 'xxxxxxxxxxxx',
        'pwd': 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
        'xdvfb': secret_code
    }

    # 根据抓包信息,构造headers
    headers = {
        'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
        'Accept-Language': 'zh-CN,zh;q=0.9',
        'Connection': 'keep-alive',
        'Content-Length': 64,
        'Content-Type': 'application/x-www-form-urlencoded',
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36'
    }

    # 获取数据,保存cooki,最后返回openner
    data = urllib.urlencode(data)
    request = urllib2.Request(login_url, data, headers)
    response = opener.open(request)
    cookie.save(ignore_discard=True, ignore_expires=True)
    return opener

终于好啦,现在我们的验证码图片就保存到image.jpg里了,我们的cookie就保存到file.txt中了。

后面,我们就可以直接通过这个opener进行访问啦~~~~

分析课表页面

我们在选课页面,单击第二页,通过抓包,我们可以看到访问页面。

好,通过抓包,我们可以看到:请求页面的URL是:

http://210.42.121.241/stu/choose_PubLsn_list.jsp?XiaoQu=0&credit=0&keyword=&pageNum=2

参数说明:

  • XiaoQu:这个参数很好理解,就是我们的校区。0表示全校,1表示1区(文理学部),2表示2区(工学部),3表示3区(信息学部),4表示4区(医学部)。
  • credit:学分
  • keyword:这个是查询的关键字,这里我们不需要使用,大家有想继续深入的,可以继续研究
  • pageNum:页码。

好,获取课程信息的URL我们也解析出来了,现在就需要我们依次爬取每个页面的信息,获取到课程信息就行了。

爬取页面

首先,这里,因为总共有24页,所以这里,我打算采用多线程进行处理,将所有爬到的课程信息保存到一个lesson_list中,然后将这个list中的信息保存到文件中即可。

构造Lesson实体类

class Lesson:
    def __init__(self, name, degree, number, teacher, jobTitle, college, textbook, year, semester, time, remarks):
        self.name = name
        self.degree = degree
        self.number = number
        self.teacher = teacher
        self.jobTitle = jobTitle
        self.college = college
        self.textbook = textbook
        self.year = year
        self.semester = semester
        self.time = time
        self.remarks = remarks

    def get_name(self):
        return self.name

    def get_degree(self):
        return self.degree

    def get_number(self):
        return self.number

    def get_teacher(self):
        return self.teacher

    def get_job_title(self):
        return self.jobTitle

    def get_college(self):
        return self.college

    def get_textbook(self):
        return self.textbook

    def get_year(self):
        return self.year

    def get_semester(self):
        return self.semester

    def get_time(self):
        return self.time

    def get_remarks(self):
        return self.remarks

    def __str__(self):
        return str(self.name + "\t" + self.degree + "\t" + self.number + "\t" + self.teacher + "\t" + self.jobTitle + "\t" + self.college + "\t" + self.textbook + "\t" + self.year + "\t" + self.semester + "\t" + self.time + "\t" + self.remarks)

构造线程类MyThread

  1. 线程类MyThread继承threading.Thread
  2. 属性说明:
    • name:线程名称
    • page:该线程要爬取的页码
    • lesson_list:爬取的课程信息保存到lesson_list中
    • opener:opener
# -*- coding: utf-8 -*-
import sys
import threading
import urllib2

from bs4 import BeautifulSoup

from Utils import get_lesson

reload(sys)
sys.setdefaultencoding('utf-8')
threadLock = threading.Lock()


class MyThread(threading.Thread):
    def __init__(self, name, page, lesson_list, opener):
        threading.Thread.__init__(self)
        self.name = name
        self.page = page
        self.lesson_list = lesson_list
        self.opener = opener

    def run(self):
        get_lessons(self.name, self.page, self.lesson_list, self.opener)


def get_lessons(name, page, lesson_list, opener):
    print name + " is starting......"
    try:
        lesson_url = "http://210.42.121.241/stu/choose_PubLsn_list.jsp?XiaoQu=0&credit=0&keyword=&pageNum=" + page
        result = opener.open(lesson_url).read().decode('gb2312', 'ignore').encode('utf-8')
        soup = BeautifulSoup(result, "html.parser")
        trs = soup.find_all(name='tr')
        threadLock.acquire()   # 互斥地写入lesson_list
        for j in range(1, len(trs)):
            tr = trs[j]
            lesson = get_lesson(tr)
            lesson_list.append(lesson)
        threadLock.release()
    except urllib2.HTTPError, e:
        print e.code

构造工具类Util

这里,需要明白一点,我们爬取地页面中,课程信息是保存到一个table中,第一个tr是表头,往后的每个tr都代表了一个lesson,所以我们在Util中定义一个方法get_lesson(tr)用来解析。

这里,具体的解析,我写的也很粗暴,详细的我就不多说了,大家看一下源码就明白了。

# -*- coding: utf-8 -*-
import cookielib
import urllib
import urllib2

from bs4 import BeautifulSoup
from xlwt import Workbook

from Lesson import Lesson


def get_lesson(tr):
    soup = BeautifulSoup(str(tr), "html.parser")
    tds = soup.find_all(name='td')

    name = tds[0].string
    degree = tds[1].string
    teacher = tds[3].string
    jobTitle = tds[4].string
    college = tds[5].string
    textbook = tds[6].string
    year = tds[7].string
    semester = tds[8].string

    soup = BeautifulSoup(str(tds[2]), "html.parser")
    number = soup.findAll("font")[0].string + str(tds[2])[str(tds[2]).index("</font>") + 7: str(tds[2]).rindex("</td>")]
    soup = BeautifulSoup(str(tds[9]), "html.parser")
    time = soup.findAll(name="div")[0].string.strip().replace(" ", "").replace("\n", "")
    soup = BeautifulSoup(str(tds[10]), "html.parser")
    remarks = soup.findAll(name="div")[0].string.strip().replace(" ", "").replace("\n", "")

    lesson = Lesson(name, degree, number, teacher, jobTitle, college, textbook, year, semester, time, remarks)

    return lesson


def init(sheet):
    sheet.write(0, 0, "课程名称")
    sheet.write(0, 1, "学分")
    sheet.write(0, 2, "剩余/最大人数")
    sheet.write(0, 3, "教师名")
    sheet.write(0, 4, "职称")
    sheet.write(0, 5, "授课学院")
    sheet.write(0, 6, "教材")
    sheet.write(0, 7, "学年")
    sheet.write(0, 8, "学期")
    sheet.write(0, 9, "上课时间地点")
    sheet.write(0, 10, "备注")


def save_lesson(lesson, sheet, row):
    sheet.write(row, 0, lesson.get_name())
    sheet.write(row, 1, lesson.get_degree())
    sheet.write(row, 2, lesson.get_number())
    sheet.write(row, 3, lesson.get_teacher())
    sheet.write(row, 4, lesson.get_job_title())
    sheet.write(row, 5, lesson.get_college())
    sheet.write(row, 6, lesson.get_textbook())
    sheet.write(row, 7, lesson.get_year())
    sheet.write(row, 8, lesson.get_semester())
    sheet.write(row, 9, lesson.get_time())
    sheet.write(row, 10, lesson.get_remarks())


def save(lesson_list):
    book = Workbook(encoding='utf-8')
    sheet = book.add_sheet("lesson")
    init(sheet)
    row = 1
    for lesson in lesson_list:
        save_lesson(lesson, sheet, row)
        row = row + 1
    book.save("lesson.xls")


def get_cookie():
    # 验证码地址和post地址
    base_url = "http://210.42.121.241/servlet/GenImg"
    login_url = "http://210.42.121.241/servlet/Login"

    # 将cookie绑定到一个opener,cookie由cookielib自动管理
    cookie = cookielib.MozillaCookieJar("file.txt")
    handler = urllib2.HTTPCookieProcessor(cookie)
    opener = urllib2.build_opener(handler)

    # 用户名和密码
    username = "xxxxxxxxxxxxxxx"
    password = "xxxxxxxxxxxxxxx"

    # 用opener访问验证码地址,获取cookie
    picture = opener.open(base_url).read()
    # 保存验证码到本地
    local = open("image.jpg", "wb")
    local.write(picture)
    local.close()

    # 输入验证码,并构造表单
    secret_code = raw_input("请输入验证码:")
    data = {
        'id': 'xxxxxxxxxxxx',
        'pwd': 'xxxxxxxxxxxxxxxx',
        'xdvfb': secret_code
    }

    # 根据抓包信息,构造headers
    headers = {
        'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
        'Accept-Language': 'zh-CN,zh;q=0.9',
        'Connection': 'keep-alive',
        'Content-Length': 64,
        'Content-Type': 'application/x-www-form-urlencoded',
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36'
    }

    data = urllib.urlencode(data)
    request = urllib2.Request(login_url, data, headers)
    response = opener.open(request)
    cookie.save(ignore_discard=True, ignore_expires=True)
    return opener

保存到文件

这里,保存到文件,我们使用了python的一个包xlwt,就来将我们的文件直接保存到excel文件中。

总结

我也就不多说什么了,思路就是我写的这样。代码我都放在了我的github(项目地址)上,大家可以去下载学习,有什么不好的地方,欢迎大家多批评指正。

猜你喜欢

转载自blog.csdn.net/RabitMountain/article/details/79188404
今日推荐