VJ 爬虫思路分享(2018年11月)


爬虫目标

帮同学写一个爬虫,给出 VJ 的账号密码和比赛的 cid,爬取本场比赛所有的提交记录及代码。
浏览器:Chrome


一、登录

在多次观察后,发现在点击登录后会有个请求 https://vjudge.net/user/login 的包,认为这个包就是包含登录信息的 http 包了!基本抓到这个包登录问题就可以解决,但是每次随着请求后的刷新这个包都会被 Chrome 丢掉…QAQ 终于再一次偶然的机会!网页突然卡了一下,果断点了浏览器的停止按钮,花了十几分钟终于抓到这个 login 的包…QAQ

General:
Request URL: https://vjudge.net/user/login	
Request Method: POST
Status Code: 200 
Remote Address: 139.162.66.202:443
Referrer Policy: no-referrer-when-downgrade

Response Headers:
access-control-allow-origin: *
content-length: 7
content-type: text/plain;charset=ISO-8859-1
date: Thu, 29 Nov 2018 09:02:17 GMT
server: nginx/1.10.3
set-cookie: Jax.Q=xxxxxxxxxx|P88KG8EEAV1E6VCO8JN3IIMA2S4TIR; Domain=.vjudge.net; Expires=Fri, 29-Nov-2019 09:02:17 GMT; Path=/  (重要信息)
status: 200
vary: Origin
vary: Access-Control-Request-Method
vary: Access-Control-Request-Headers

Request Header:
:authority: vjudge.net
:method: POST
:path: /user/login
:scheme: https
accept: */*
accept-encoding: gzip, deflate, br
accept-language: en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7
cache-control: no-cache
content-length: 36
content-type: application/x-www-form-urlencoded; charset=UTF-8
cookie: _ga=GA1.2.1529669933.1542380217; JSESSIONID=6D543E63BF587054D4FDF357F435D8FB
origin: https://vjudge.net
pragma: no-cache
referer: https://vjudge.net/
user-agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36
x-requested-with: XMLHttpRequest

Form Data:
username: xxxxxx(你填写的用户名和密码,明文)
password: xxxxxx

事后百度查到,可以点一下 Preserve log(如图所示)来保存刷新之前的包!Preserve log

好啦抓到这个包之后,就能很容易的知道下面的信息了:

登录请求包主体部分包含两行信息:username 和 password,分别是明文的账号和密码。

之后进行一个需要身份验证的动作,比如打开一个你已经输入过密码的比赛界面(如果之前输入过密码再次进入就无需输入密码,所以需要身份验证),发现此包的内容如下:比赛页面包
结合这两个图可以得出结论:

login 包返回的 set-cookie 中用来身份验证的信息是 Jax.Q 这个 cookie,格式为 “username|session”,每次请求时带上此 cookie 即可进行身份验证

此部分任务完成。

二、比赛页面

有了上面的结论,给出一个 cid,cookie 带上 Jax.Q,加上其他的请求头,就可以很容易的得到比赛页面啦。(即请求一个 https://vjudge.net/contest/[cid] 的 url )
还注意到请求比赛页面的返回包主体也是有内容的,是一个 json 包,包含以下内容:

  1. id:即请求的 cid。
  2. title:比赛名
  3. begin:距离某个时间点的毫秒数(懒得去查是哪个时间点了,就是一个开始时间的标识)
  4. length:比赛市场,以毫秒为单位
  5. isReplay:不详…
  6. participants:参赛人员,也是一个 json 数据,里面包含每一个参赛人员的用户标识符和用户昵称。
  7. submissions:此场比赛的所有提交记录,为一个列表每一项是一个提交记录;列表里的每一项又是一个列表,记录了每一个提交记录的相关信息:
    [用户标识符,
    题目序号,
    返回结果代码( 0 是 wrong answer,1 是 accept等),
    距开始经过的时间(以秒为单位)
    ]

三、迷茫 & 分析

打开了比赛界面,下面就应该获取代码了。从哪里爬呢?

在这里插入图片描述

于是发现,每个提交记录点开左上角都有一串数字,点开后会打开这个界面:
代码页面(网页)
如果爬虫能打开这个页面,然后拿出里面的 html 代码就可以了。
但是,这个 html 解析过的代码,已经被各种标签和换行包围了,肯定是被 VJ 上的一块专门负责语法高亮的 JS 代码解释过了。那么没处理之前的源代码是从哪获得的呢?
来看看这个页面的数据包内容有什么
果然,请求这个页面的返回包主体就有代码。
看看这个网页的 url:https://vjudge.net/solution/[runId]
也就是说,只要能获取所有的 runId,就能爬出代码了。

下面的任务就是获取此账号在此场比赛所有提交的 runId,再用每个 runId 分别请求上面的 url。

四、获取 runId

要获取 runId,只能通过这个窗口获得。
在这里插入图片描述
也就是说要分析一个分页的 Status …
既然把数据分页,肯定也是先把数据传过来,再放在 html 里分页吧,那么一开始传来的数据是哪来的呢?(思路类似于上一步获取源代码)
然后发现,点击 Status 后,会有一个请求 https://vjudge.net/status/data/ 的数据包。
既然查询参数不在 url 里,那肯定在请求主体里,主体里发现了几个有用的参数:
contestId:查询的 cid
un:即 username
res:返回状态,即代表wrong answer、accept等的 0 - 7 的代码。
这肯定就是查询参数了,之后在 Status 试了一下带条件的查询,印证了上面的想法。
这样就可以查询此用户在本场比赛的 runId 了。
本以为大功告成,但是碰到了下面问题…


五、解码

获取了所有的 runId,在请求第三步的 url,返回的 json 数据本应该包含代码。但是确是一堆乱码…
再仔细看这次包的内容,发现了这个玩意:在这里插入图片描述

content-encoding 为 gzip,gzip是一种加密方式,是不是主体的内容被加密了呢?
在网上一查,果然确是是需要 gzip 解密才能获取原本。在 Python3 中用 gzip 和 io.BytesIO 两个包便可以解决此问题。

到此大功告成!


过程小结

  1. 请求 https://vjudge.net/user/login,请求主体有 username、password。
  2. 从返回包中的 set-cookie 中获取本次登录的 Jax.Q,包含 username 和 session。之后所有的请求,都要在 cookie 中带上 Jax.q 这一项。
  3. 请求 https://vjudge.net/status/data/ ,请求主体 un 设为 此账号的username,contestId设为 cid,获取所有的 runId。
  4. 请求 https://vjudge.net/solution/[runId] ,返回的数据包中有加密过的代码。
  5. 利用 Python3 的 io.BytesIO 和 gzip 两个包解密,即可获得代码。

收获

  1. 在探索的过程中发现所有有用的源数据包都叫做 xhr 包,全称 XMLHttpRequest ,是一种用来传输数据的包。基本都是 xhr 传过来数据,html 用来展示数据。以后如果要找展示在 html 里的数据先找 xhr 包。
  2. 理解了 session、cookie 在登录中的作用,即用来身份验证。
  3. Chrome 中 Preserve log 用来保存刷新之前的包。
  4. content-encoding 用来表示数据加密方式。
  5. 在 Chrome 中来回两个包放在了一次请求中,请求头和主体、返回头放在 Headers 一栏,返回主体在 Response 一栏。
  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值