美文网首页菜鸡爬虫修炼史python热爱者
爬取学校教务处网站,提取并保存信息

爬取学校教务处网站,提取并保存信息

作者: Dash_chan | 来源:发表于2017-12-17 21:00 被阅读465次

最近开始用简书记录学习过程的点滴。等以后自己学会建博客再移到博客上去吧~

工具:
python3.6.3
requests
BeautifulSoup
xlwt

爬取学校教务处
学了python基础语法,requests和beautsoup,没有练手过,遂到教务处一展拳脚。我学校的教务处登录比较简单,没有验证码,然而我还是不会用post。。。。。

1:构造请求
这里需要伪造一下浏览器:
这里尽显我爬虫渣本色,直接在谷歌浏览器里开发者工具中复制的header

header = {"User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36"}

此外,登录需要密码账号,我试图用requests的post方法,构建账号密码信息,然而一知半解,在此记录过程,希望有高手解答:

a.打开登录页面-F12-Network抓包,如图:


image.png

b. 抓包
抓包还看了不少博客,学的三脚猫的功夫:先故意输错密码试试看


image.png

可以看到network中抓取到数据流,点开Form Data, userName和pwd应该就是账号和密码,但是pwd后面这串是什么鬼啊???加密???还有这个sign后面那串数字,我也看不懂,所以post方法暂时行不通,可以留着以后慢慢研究,或者有大神解释解释那是极好的。

穷则思变,变则通达,post不行,我就不学了吗?那肯定不会。在网上看到了另外一招,对新手及其友好的,利用cookies进行登录。

a. 输入账号密码,登录教务处页面,还是打开网络监听F12-Network,点击第一个选项,它是此页中第一个数据流(或者其他叫法,我极其不专业。。。),在右侧找到cookies,如下图


image.png

关于cookies的原理我也不懂,看文章说是用户与服务器之间的一种凭证,应该就是短时间生成的一种凭证,只要这个凭证有效,那么用户就可以不用登陆就可以访问服务器上面的数据。看它这么乱,应该是用方法加密了,暂且就这么理解吧。

b. 复制这段cookies,我们就可以制作cookies了。使用如下代码:

cookies = {}
raw_cookies = "ASP.NET_SessionId=2gq0mryer************; UserTokeID=f716cffe-************-a84d-**********c"
for line in raw_cookies.split(';'): #用';'对字符串分割
        key, value = line.split('=', 1)
        cookies[key] = value

这个方法我是网上学到的,不过它的作用其实就是将原生的cookies构造成以键值对形式的字典,所以你也可以直接这样:

cookies = {'ASP.NET_SessionId': '2gq0mryer************', 'UserTokeID': 'f716cffe-************-a84d-**********c'}

这样手动将复制下来的raw_cookies构造成cookies。

接下来是获取URL,我们打开成绩页面,同样也是用F12去捕捉成绩页面的URL:



或者其实可以直接从网址那里复制???不是很懂,因为有网友说其实获取真实URL会有点麻烦。。。这里也要回头复习,什么是真实URL?怎么获取?嗯,记一下。

到这里我们已经把所有请求页面要包含的信息都准备好,可以开始写请求代码了。我用的是requests库,感觉要比urllib2方便。

import requests
from bs4 import BeautifulSoup

header = {"User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36"}
cookies = {}
raw_cookies = "ASP.NET_SessionId=2gq0mryer************; UserTokeID=f716cffe-************-a84d-**********c"
for line in raw_cookies.split(';'): #用';'对字符串分割
        key, value = line.split('=', 1)
        cookies[key] = value
url = "http://202.115.133.***:805/********/Score/ScoreList.aspx"

r = requests.get(url, headers = header, cookies = cookies)

这样我们就完成了请求,接下来解析页面。

2:解析页面
打开成绩页面,F12下看Element选项,或者网页源代码,我们可以看出成绩页面的结构:如下图:


image.png

右键审查元素,定位到元素标签。哇,这么多<li class="item">...</li>标签,应该就是每门课的成绩信息了。我们点开具体看一下:


image.png
果然,没毛病老铁。

接下来就好办了,思路是:用靓汤找到所有的<li class="item">...</li>标签,然后循对每一个<li class="item">...</li>里面的信息提取。嗯,上代码:

soup = BeautifulSoup(r.text, "html.parser")
items = soup.findAll('li', attrs = {'class': 'item'}
for item in items:
        print(item.text)

我们先来试试看输入结果:


image.png

你妹!!!什么鬼?!!!这一大堆的空格我可不能输进Excel啊!!!
试试用split()切开:

soup = BeautifulSoup(r.text, "html.parser")
items = soup.findAll('li', attrs = {'class': 'item'}
for item in items:
        print(item.text.split())
out:
image.png

嗯~~~很好,列表形式的数据就好操作多了。为了能更加愉快地玩耍,我们可以把这些列表全放到一个新的列表里:

data_list = []
for item in items:
        data_list.append(item.text.split())

看看输出:

print(data_list)
image.png

很好,接下来就只要把数据写进Excel里面就成啦

3:保存数据
写入Excel操作我用到了xlwt,安装这个库也是有点小坑,具体解决方案网上有很多,不再赘述。上代码:

book = xlwt.Workbook()
sheet1 = book.add_sheet('sheet1', cell_overwrite_ok = True)
#列表的每一行写入一门课成绩,最开始的行为0行,写入表格头:
heads = ['学期', '课程编码', '课程名称', '教师', '学分', '成绩', '成绩类型', '绩点', '入库人', '入库时间']
#这里write方法接受3个参数,分别为行、列、值。表格头部信息在第0行
i = 0
for head in heades:
        #依次将heades列表的每一个元素写入表格中
        sheet1.write(0, i, head)
        i += 1
#从第1行开始写入成绩信息
m = 1
#对大列表里每一个小列表进行遍历,小列表保存有一门课的成绩信息,这样就能把所有课程成绩信息循环到。
for list in data_list:
        n = 0
        #对小列表里每个元素进行遍历
        for info in list:
                #将每个元素写入表格
                sheet1.write(m, n, info)
                n += 1
        m += 1
book.save('grade.xls')

这样全部代码就完成啦!下面是完整代码,本水笔代码代码像屎一样,没有一丁点封装。。。。。后面有时间再慢慢优化

import requests
from bs4 import BeautifulSoup
import xlwt

header = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36'}
raw_cookies = "ASP.NET_SessionId=2gq0mryer0o34wrmurek2dm3; UserTokeID=37efd17b-5a15-409f-93c5-8f9566d2b21d"

cookie = {}
for line in raw_cookies.split(';'):
    key, value = line.split("=", 1)
    cookie[key] = value
url = "http://202.115.133.173:805/SearchInfo/Score/ScoreList.aspx"
r = requests.get(url, headers=header, cookies = cookie)
r.encoding = 'utf8'

data_list = []
soup = BeautifulSoup(r.text, "html.parser")
items = soup.find_all('li', attrs={'class': 'item'})
for item in items:
    data_list.append(items.text.split())

book = xlwt.Workbook()
sheet1 = book.add_sheet('sheet1', cell_overwrite_ok = True)
heads = ['学期', '课程编码', '课程名称', '教师', '学分', '成绩', '成绩类型', '绩点', '入库人', '入库时间']
i = 0
for head in heads:
    sheet1.write(0, i, head)
    i += 1

m = 1
for list in data_list:
    n = 0
    for data in list:
        sheet1.write(m, n, data)
        n += 1
    m += 1
book.save("chenzhida.xls")
print("录入成功")

成果如下:


image.png

遗留问题:
有些课程的信息不全,比如没有教师的名字等等,这样录进Excel的时候信息会对不上表头。应该可以用某种替换方法,给空格占个位置,这样录进去的格式就能对的上表头。后面再处理吧~

以下是本次爬取过程中遇到的一些坑,还有困惑,写下来提醒自己以后要解决:

  1. 使用cookies模拟登录自然会省事点,但是由于这个凭证只能短期有效,当需要爬取数据很多的时候,可能需要爬取十几天或者更久,这时cookies就不好用了,容易挂掉。这里需要学习post,学习分析账号密码提交,要是有加密怎么破解?遇到验证码怎么办?FROM DATA中每一项数据代表什么?遇到动态页面怎么破?(有大神教吗?)
  2. 如何获取真实URL,真实URL是什么?
  3. 表格数据有缺失怎么破
  4. 保存数据到本地。要学习常用的mongoDB。
  5. 学习其他的解析工具,Xpath
  6. 学习scrapy。

另外,此次保存数据还花了老子大部分时间,记录一下犯蠢的过程:
一开始我的思路是,把所有的课程成绩信息提取出来,放到一个总的表格里,然而当我实际做的时候,我发现:

items = soup.findAll(r.text, "html.parser)
data_list = []
for item in items:
        data_list.append(item.text)
        print(data_list)

返回的是:



后来发现是输出的地方错了:应该是

items = soup.findAll(r.text, "html.parser)
data_list = []
for item in items:
        data_list.append(item.text)
print(data_list)

for循环没掌握好。。。。
但是这样输出的是:


image.png

还是不行呀,这些“ \xa0\r\n,\n\r\n ”是什么鬼???(其实可以用在末尾追加.spilt()方法,可以实现去掉空格和换行符)

然后我又想到了可不可以用正则表达式提取内容?把所有内容提取出来放到一个表格中,和原来不同的是,这里大表格里面是没有小表格的。我们可以取10个元素取10个元素这样去做小表格。
又开始折腾了:

infos = re.findall(r'<div.*?">(.*?)</div>', str(items))
print(infos)

结果:


image.png

emmmmmm......exo me????
后来仔细一看网页源代码:


image.png
哦,原来有空格,而 . 是除了空格以外的任意字符,一般都要加re.S
infos = re.findall(r'<div.*?">(.*?)</div>', str(items), re.S)
print(infos)

结果:


image.png

what the 你妹!这不和原来一样了吗?不过确实是一个大表格,但是
\xa0\r\n \r\n 肿么破?机智的我想到用replace()试试看:

infos = re.findall(r'<div.*?">(.*?)</div>', str(items), re.S)
for info in infos:
        print(str(info).replace('\xa0\r\n', '').replace('\r\n', '').strip())
image.png

我好像发现了什么!!!原来的遗留问题貌似可以解决的!!!

list = []
infos = re.findall(r'<div.*?">(.*?)</div>', str(items), re.S)
for info in infos:
    list.append(str(info).replace('\xa0\r\n', '').replace('\r\n', '').strip())
#把list按照每次取10个的数量,做成小表格,然后把这些小表格添加到new_list里面方便操作,这样的好处是,会把缺失信息的地方给站位,后面录进Excel的时候就不会对不上表头。
new_list = [list[i: i+10] for i in range(0, len(list), 10)]
print(new_list)

结果:


image.png

哈哈哈那我直接放完整代码了

# -*- coding: utf-8 -*-
import requests
import  re
from bs4 import BeautifulSoup
import xlwt

header = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36'}
raw_cookies = "ASP.NET_SessionId=2gq0mryer0o34wrmurek2dm3; UserTokeID=6412ebc3-5fde-44f5-b5e0-d0de28125591"
url = "http://202.115.133.173:805/SearchInfo/Score/ScoreList.aspx"
cookies = {}
for line in raw_cookies.split(";"):
    key, value = line.split("=", 1)
    cookies[key] = value

r = requests.get(url, headers = header, cookies = cookies)
print(r.status_code)
r.encoding = 'utf8'

data_list = []
soup = BeautifulSoup(r.text, "html.parser")
items = soup.find_all('li', attrs = {'class': 'item'})

list = []
infos = re.findall(r'<div.*?">(.*?)</div>', str(items), re.S)
for info in infos:
    list.append(str(info).replace('\xa0\r\n', '').replace('\r\n', '').strip())
new_list = [list[i: i+10] for i in range(0, len(list), 10)]
print(new_list)

book = xlwt.Workbook()
sheet1 = book.add_sheet('shee1', cell_overwrite_ok=True)

heads = ['学期', '课程编码', '课程名称', '教师', '学分', '成绩', '成绩类型', '绩点', '入库人', '入库时间']
s = 0
for head in heads:
    sheet1.write(0, s, head)
    s += 1

m = 1
for lists in new_list:
    n = 0
    for data in lists:
        sheet1.write(m, n, data)
        n += 1
    m += 1
book.save("stander.xls")
print("录入成功")

成果:


image.png

这样有些没有信息的地方也可以用空白来站位。
finish!

相关文章

网友评论

    本文标题:爬取学校教务处网站,提取并保存信息

    本文链接:https://www.haomeiwen.com/subject/gjjjwxtx.html