欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

强智系统爬虫分析

程序员文章站 2022-04-27 23:43:10
...

强智系统爬虫分析

一、登录分析

我校使用的教务管理系统是叫做强智系统,有一天我就突发奇想想要搞一个爬虫去给他搞一搞。
1.刚开始我以为是非常简单的一个post请求就解决的事情,我就post了一个

data = {
		username: 'xxxx',
		password: 'xxxx',
		RANDOMCODE: 'XXXX',
		}

由于我还是太年轻,没有经历过反爬虫的毒打,果然返回了登陆失败。然后我就看了下网页源代码
强智系统爬虫分析
咋回事?这玩意就提交了一个encoded和RANDOMCODE,竟然没有提交username和password。根据我多年的后端经验(假的,ε=ε=ε=┏(゜ロ゜;)┛)肯定这个encoded就是password和username进行加密编码后的产物。果然当我阅读他后面的一段js代码我发现了隐秘。
强智系统爬虫分析
从中我们可以看到它通过一个叫encodeInp的函数进行加密(转码)然后把这两个通过%%%进行连接(好智障的一个设定)。然后我再一个叫做conwork.js的js文件中发现了这个函数。
强智系统爬虫分析
强智系统爬虫分析
找到这个文件就好解决了,我通过PyExecJs来调用这个js文件里面的函数。
登录代码如下

'''简单解析验证码'''
def parse_verity_code(session, img_url):
    img_content = session.get(img_url)
    img = Image.open(BytesIO(img_content.content))
    img.save('a.png')
    verify_image = Image.open('a.png')
    code = pytesseract.image_to_string(verify_image)
    time.sleep(2)
    return code


'''
对账号密码进行编码
'''

def make_user_token(username, password):
    with open('conwork.js') as f:
        ctx = execjs.compile(f.read())
        username_encode = ctx.call('encodeInp', username)
        password_encode = ctx.call('encodeInp', password)
    token = username_encode + '%%%' + password_encode
    print(token)
    return token    

二、其他分析

其实在登录之后事情就变的简单多了,这管理系统没有那么多的反爬机制,所以你想干啥就能干啥。下面完整代码展示下,我这里隐去我们学校的网站

# encode: utf-8
import re
from io import BytesIO
import requests
from lxml import etree
from PIL import Image  # 用于显示图片
import pymongo
import pytesseract
import time
import execjs

#
# MONGO_CLIENT = pymongo.MongoClient("mongodb://127.0.0.1:27017")
# mydb = MONGO_CLIENT['xxu_jwxt']
# mycol = mydb['score_list']

BASE_URL = "https://jwxt.xx大学.edu.cn"

SCORE_FOR_USER = []

USERNAME = '2017xxxxxx'
PASSWORD = 'xxxxxxxxxx'


def parse_verity_code(session, img_url):
  img_content = session.get(img_url)
  img = Image.open(BytesIO(img_content.content))
  img.save('a.png')
  verify_image = Image.open('a.png')
  code = pytesseract.image_to_string(verify_image)
  time.sleep(2)
  return code


'''
对账号密码进行编码
'''


def make_user_token(username, password):
  with open('conwork.js') as f:
      ctx = execjs.compile(f.read())
      username_encode = ctx.call('encodeInp', username)
      password_encode = ctx.call('encodeInp', password)
  token = username_encode + '%%%' + password_encode
  print(token)
  return token


'''
  解析登录页面
'''


def parse_login(url):
  headers = {
      'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36'
  }
  session = requests.session()
  resp = session.get(url, headers=headers)
  text = resp.text

  html = etree.HTML(text)
  img = html.xpath("//img/@src")[1]
  img_url = BASE_URL + img
  while True:
      try:
          code = parse_verity_code(session, img_url)
          code = re.sub("[^\d\w]", '', code)
          print("验证码:" + code)
          login_url = BASE_URL + "/jsxsd/xk/LoginToXk"
          print(login_url)
          '''
              用户名和密码会加密后以%%%连接
          '''
          encoded = make_user_token(USERNAME, PASSWORD)
          data = {
              'encoded': encoded,
              'RANDOMCODE': code,
          }
          print(data)

          rs = session.post(login_url, data)  # 进行登录操作

          # 成绩列表
          score_page_url = 'https://jwxt.xxu.edu.cn/jsxsd/kscj/cjcx_list'

          resp = session.get(score_page_url, headers=headers)
          score_list = etree.HTML(resp.text)
          data_list = score_list.xpath('//table[@id="dataList"]')[0]
          scores = data_list.xpath(".//tr")[1:]
          for score in scores:
              tds = score.xpath(".//td")
              goal_data = {
                  'id': tds[0].text,
                  'term': tds[1].text,
                  'cno': tds[2].text,
                  'cname': tds[3].text,
                  'score':  tds[4].xpath('.//a/text()')[0],
                  'point': tds[5].text,
                  'total_point': tds[6].text,
                  'GPA': tds[7].text,
              }
              SCORE_FOR_USER.append(goal_data)
              # mycol.save(goal_data) #  保存到mongo数据库中
              print(goal_data)
          if SCORE_FOR_USER:  # 验证码正确 跳出循环结束程序
              break
      except:
          print("验证码错误")


def main():
  url = "https://jwxt.jsu.edu.cn/jsxsd/"
  parse_login(url)


if __name__ == '__main__':
  main()