justtreee / blog

31 stars 8 forks source link

【python爬虫笔记】校各部门网站模拟登录与数据获取 #3

Open justtreee opened 6 years ago

justtreee commented 6 years ago

环境:chrome,python 3.5

一、正方教务管理系统

1. 目标分析

default

首先可以看到我们需要填写以下字段:

  • 用户名
  • 密码
  • 验证码
  • 身份选择

需要注意的就是验证码: 可以知道验证码是以图片的方式浮现在文本框上的。这里选择找到验证码的图片链接,并下载到本地,通过用户手动输入验证码来完成登录。

之后可以尝试一下图像识别的第三方库,实现自动填写验证码。

2. 数据抓取

(1) 抓取验证码

对验证码右键单击检查,可直接定位在验证码的相应信息上。

checkurl

得到验证码的图片链接:

(2) 抓取post数据

chrome下按F12打开开发者工具

这里给一个技巧,我们可以先故意输入一个 错误的值 来追踪一下我们究竟post了哪些值 打开 Chrome开发者工具 --- Networks --- 勾选 Preserve log 输入一些值,点击 登录按钮, 在点开右边的 Headers 拉倒最后的 FromData: 这里就是我们提交数据:

header

这个字典里,我们很容易可以看到我们需要自己填写的值: post的数据一般是通过键值对的形式传到服务器的,一般是字典或json格式

而第一个数据是如何得到的?在登录界面的html页面中。

viwhtml

可见第一个数据在登录界面html中,我们模拟登录时把这个数据提出来。就行了。

这一长串随机的值,实际上是正方系统的一个简单的验证手段。

(3) 获取课表

通过浏览器登录之后,进入 /xs_main.aspx?xh=********** 页面,再转入课表页面,地址栏的网页链接并没有变化,但真正的课表链接藏在html里面。同理在课表处右键检查定位到htmlkburl

(4) 代码

#-*-coding:utf-8-*-
import os
import re
from lxml import etree
import requests
import sys
from bs4 import BeautifulSoup
from PIL import Image
#初始参数,自己输入的学号,密码。
studentnumber = input("学号: ")
password = input("密码: ")

#得到__VIEWSTATE的值。
s = requests.session()
url = "http://jw.****.edu.cn/default2.aspx"
response = s.get(url)
selector = etree.HTML(response.content)
__VIEWSTATE = selector.xpath('//*[@id="form1"]/input/@value')[0]

#获取验证码并下载到本地
imgUrl = "http://jw.****.edu.cn/CheckCode.aspx?"
imgresponse = s.get(imgUrl, stream=True)
#print (s.cookies)
image = imgresponse.content
DstDir = os.getcwd()+"\\"
try:
    with open(DstDir+"tcode.jpg" ,"wb") as jpg:
        jpg.write(image)
except IOError:
    print("IO Error\n")
finally:
    jpg.close

# 打开验证码图片
image = Image.open('{}/tcode.jpg'.format(os.getcwd()))
image.show()
#手动输入验证码
code = input("验证码: ")

#构建post数据
data = {
"__VIEWSTATE":__VIEWSTATE,
"txtUserName":studentnumber,
"TextBox2":password,
"txtSecretCode":code,
"Button1":"",
}
#提交表头,里面的参数是电脑各浏览器的信息。模拟成是浏览器去访问网页。
headers = {
    "User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.110 Safari/537.36",
}

#登陆教务系统
response = s.post(url,data=data,headers=headers)
print ("成功进入")

#得到登录信息
def getInfor(response,xpath):
    content = response.content.decode('gb2312') #网页源码是gb2312要先解码
    selector = etree.HTML(content)
    infor = selector.xpath(xpath)[0]
    return infor
#获取学生基本信息
text = getInfor(response,'//*[@id="xhxm"]/text()')
text = text.replace(" ","")
print (text)

#获取课表,kburl是课表页面url,为什么有个Referer参数,这个参数代表你是从哪里来的。就是登录后的主界面参数。这个一定要有。
kburl = "http://jw.****.edu.cn/xskbcx.aspx?xh="+studentnumber+"&xm=%D5%C5%B8%DB&gnmkdm=N121603"
headers = {
"Referer":"http://jw.****.edu.cn/xs_main.aspx?xh="+studentnumber,
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.110 Safari/537.36",
 }
response = s.get(kburl,headers=headers)

#html代表访问课表页面返回的结果就是课表。下面做的就是解析这个html页面。
html = response.content.decode("gb2312")
selector=etree.HTML(html)
content = selector.xpath('//*[@id="Table1"]/tr/td/text()')
for each in content:
   print (each)

(5) 结果

tst1 tst2

TODO: 3. 验证码的自动识别

二、校体育部网站

校体育部这个网站有点非主流,与csdn等博客上最常见的教务系统登录不太一样,是个很好的练手对象。

1. 模拟登录

首先是通过Fiddler 4对目标网站进行登录抓包(应该是这个词吧)。

default

关键点1: 体育部的登陆页面并不是/security/login.do,而是/login.do关键点2: 在输入账号密码之后,还有btnlogin.xbtnlogin.y这两个属性,大胆猜测这是点击按钮的动作,而后面值就是横纵坐标。

登录成功并获取首页html

import urllib.request, urllib.parse, urllib.error
import http.cookiejar
import requests
from bs4 import BeautifulSoup
import bs4
LOGIN_URL = 'http://211.69.129.116:8501/login.do'
# ===========关键点:体育部网站的真正登陆页面并不是网站那栏,在fiddler中显示为该网址===========
get_url = 'http://211.69.129.116:8501/jsp/menuForwardContent.jsp?url=stu/StudentSportModify.do'
#get_url = 'http://211.69.129.116:8501/'  # 利用cookie请求访问另一个网址
values = {'action': 'username', 'username': '2016317200113', 'password': '888888', 'btnlogin.x': '30', 'btnlogin.y': '11'}
# ===========关键点:在fiddler的action中还有两行btnlogin的信息,将这个点击按钮的动作加入到values中===========
postdata = urllib.parse.urlencode(values).encode()
user_agent = r'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.157 Safari/537.36'
headers = {'User-Agent': user_agent}

cookie_filename = 'cookie_jar.txt'
cookie_jar = http.cookiejar.MozillaCookieJar(cookie_filename)
handler = urllib.request.HTTPCookieProcessor(cookie_jar)
opener = urllib.request.build_opener(handler)

request = urllib.request.Request(LOGIN_URL, postdata, headers)
try:
    response = opener.open(request)
    html = response.read().decode()
    #print(response.read().decode())
except urllib.error.URLError as e:
    print(e.code, ':', e.reason)
#================html格式化================
soup = BeautifulSoup(html)
print(soup.prettify())   
#==========================================

# TODO: Creat List
ulist = []
soup = BeautifulSoup(html, "html.parser")
for tr in soup.find('tbody').children:
    if isinstance(tr, bs4.element.Tag):
        tds = tr('td')
        ulist.append([tds[0].string, tds[1].string])
print("==================LIST======================")
for i in range(5):
    u = ulist[i]
    print("{:^10}\t{:^6}", format(u[0], u[1]))
#=================unfinished=================

数据提取

但是获取的还是原始的html文本,没有依据标签进行数据提取。 未完待续

参考链接: 从零开始写Python爬虫抓取课程表