首页 > 编程语言 >Python爬虫案例与实战:爬取源代码练习评测结果

Python爬虫案例与实战:爬取源代码练习评测结果

时间:2024-08-07 23:26:16浏览次数:17  
标签:请求 登录 Python base64 爬取 session 提交 源代码 id

Python爬虫案例与实战:爬取源代码练习评测结果

本章案例将介绍用 Python编写程序实现简单网站的模拟登录,然后保持登录后的网页会话,并在会话中模拟网页表单提交,之后使用 Requests库的高级特性爬取提交之后的返回结果。在HTTP网页中,如登录、提交和上传等操作一般通过向网页发送请求实现。通过对网页抓包分析,判断请求操作的类型,进而用Python的Requests库构建一个网页请求,模拟实际的网页提交。
4.1网站分析
POJ是老牌的供ACM/ICPC(大学生程序设计竞赛)选手在线提交程序源代码进行评测的练习平台,提交代码后需要跳转至网站的评测状态页面,再寻找用户所提交代码的评测结果。由于这种操作相对麻烦,本案例将通过编写模拟登录网站,并且通过表单提交的方式,上传评测用代码,提交之后发送请求,获取评测结果输出。
为分析登录的请求方式,在登录界面,务必在输入账号密码前,打开浏览器的开发者模式,找到Net Work 选项。再登录,此时开发者模式下会显示登录后的各种请求,找到login项,如图4-1所示,容易分析得出登录时的请求方式是POST请求。
在这里插入图片描述
页面往下拉,登录时 POST请求的内容如图4-2所示。可以看到 POST 发送的内容,有4个参数,前两个是用户的I和密码,后两个参数固定。需注意在编写爬虫程序时,POST内容的参数值是多少。
因为只看POST请求返回结果并不能判断是否登录成功,需要分析网页验证是否登录成功。其中一种常见的验证方法是访问代码提交界面。如果未登录成功,则会弹出登录框提示登录,如图4-3所示。如果登录成功,则通过网页元素分析,查看用于POST请求的form(表格)处的操作是login(登录)还是submit(提交),如图4-4所示。对比分析得出登录状态不同时HTML 文本的不同。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
与登录成功时的操作相似,想要分析代码提交页面,必须提前打开开发者界面,单击“提交”按钮后抓包,如图4-5所示。在代码提交POST 请求的内容中,参数分别代表题目ID、提交所用语言(在可选语言列表中选择相应的下标,如4代表 C++语言、5代表C语言)、源代码和固定参数。注意,源代码提交方式采用 base64编码,属于HTTP网页中常见的表单提交方式和内容加密方式。
最后,是获取评测结果,在实际中,POJ的评测量很大,公屏评测结果刷新很快,只能通过手动输入用户ID的方式查看特定用户的评测结果,评测结果显示界面的URL 的格式为“poj.org/status?problem_id=&.user_id=&.result=&.language=”,看出是采用 GET 方式请求结果,如图4-6所示。通过分析网页元素,可以发现一条评测结果位于HTML 文本节点的子节点,此时想要获取最新结果,只需要访问第一个子节点,再遍历其子节点获取具体评测结果。
在这里插入图片描述
在这里插入图片描述

4.2编写爬虫

按以上分析网页和操作的思路,可以编写爬虫,具体操作如下。
(1)main()函数部分用于创建访问会话,并将验证登录,提交代码。注意,将获取评测结果的函数的接口放在 main()函数中。

if __name__ == '__main__':
    user_name = 'ajshederay00616'
    logindata = {'user_id1': 'ajshederay00616',
                 'password1': '114514yjsnpi', 'B1': 'login', 'url': '%2F'}
    header = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.100 Safari/537.36'}
    session = requests.session()
    login_req = session.post('http://poj.org/login',
                             data=logindata, headers=header)
    if login_req.status_code != 200:
        print('Failed to post the login request!')
        exit(1)
    if loginCheck(session):
        print('Welcome! %s\n--------------------' % user_name)
    else:
        print('Failed to log in!Please Retry!')
        exit(1)
    problem_id, language = input(
        'Enter the Problem_id and Language:\n').split()
    print('--------------------')
    submitdata = createSubmit(problem_id, language)
    submit_req = session.post('http://poj.org/submit', data=submitdata)
    if submit_req.status_code != 200:
        print('Failed to submit the source code!')
        exit(1)
    queryURL = 'http://poj.org/status?problem_id=%s&user_id=%s&result=&language=' % (
        problem_id, user_name)
    sleep(2)
    query_req = requests.get(queryURL)
    info = getResult(query_req)
    printResult(info)
    session.close()

requests.session()方法是爬虫中经常用到的方法,在会话过程中自动保持 cookies,不需要自己维护cookies内容。如果不用此方法,则需要在第一次网站请求时,一个URL 会获取cookie,在第二次网站请求时,校验第一次请求获取的 cookie。requests.session()方法可以做到在同一个session实例发出的所有请求中都保持同一个cookie,相当于浏览器在不同标签页之间打开同一个网站的内容一样,使用同一个cookie。这样就可以很方便地处理登录时的cookie问题。
[提示]会话对象(session)是Requests的高级特性,除了上述这个用法,Requests库的高级用法还包括请求与响应对象、准备的请求(Prepared Request)、SSL证书验证、客户端证书、CA证书、响应体内容工作流、保持活动状态(持久连接)、流式上传、块编码请求、POST多个分块编码的文件、事件挂钩、自定义身份验证、流式请求、代理、SOCKS、合规性、编码方式、HTTP动词、定制动词、响应头链接字段、传输适配器、阻塞和非阻塞、Header排序等。
(2)登录检查函数。

def loginCheck(session):
    html = session.get('http://poj.org/submit?problem_id=1000')
    sleep(1)
    if html.status_code != 200:
        return False
    soup = BeautifulSoup(html.content, 'html.parser')
    for td in soup.form.find_all('a'):
        if td['href'] == 'submit':
            return True

(3)创建提交代码POST请求的参数,以及对代码进行 base64编码。

def createSubmit(problem_id, language):
    submitdata = {'problem_id': '1000', 'language': 0,
                  'source': '', 'submit': 'Submit', 'encoded': 1}
    language_map = {'G++': 0, 'GCC': 1, 'Java': 2,
                    'Pascal': 3, 'C++': 4, 'C': 5, 'Fortran': 6}
    submitdata['problem_id'], submitdata['language'] = problem_id, language_map[language]
    file_path = tkinter.filedialog.askopenfilename()
    print('File %s selected, ready to submit!' % file_path)
    print('--------------------')
    code_file = open(file_path, 'r', encoding='utf-8')
    submitdata['source'] = base64encode(code_file.read())
    return submitdata

base64编码是网络上最常见的用于传输8bit字节码的编码方式之一,base64编码就是一种基于64个可打印字符来表示二进制数据的方法。base64编码是从二进制到字符的过程,可用于在HTTP环境下传递较长的标识信息。采用 base64编码具有不可读性,需要解码后才能阅读。关于 base64的编码规则:base64要求把每3个8bit的字节转换为4个6bit的字节(3X8=4X6=24),然后把 6bit再添两位高位0,组成4个8bit的字节。也就是说,转换后的字符串理论上将要比原来的长1/3。
例如,要对字符串abc进行 base64编码,首先将abc对应的ASCII编码97、.98、99,写成3个二进制位的形式,即01100001、01100010、01100011,共24位,按6位为一组可分为4组,在每组的高位补上00,经过转换,转换之后为00011000、00010110、00001001、00100011,对应base64索引值为24、22、9、35,参照 base64编码表,编码后得到的字符串为YWJj,完成编码。Python自带有base64库,可以使用库函数对字符串进行base64编码和解码。
(4)在提交完成之后获取评测结果,最后输出。

def getResult(req):
    soup = BeautifulSoup(req.content, 'html.parser')
    for tb in soup.find_all('table'):
        if tb.get('class') != None:
            if tb.get('class')[0] == 'a':
                score_table = tb
                break
    for row in score_table.find_all('tr'):
        if row.get('align') != None:
            result = row
            break
    info = result.find_all('td')
    return info
def printResult(info):
    printLs = ['Run ID', 'User Name', 'Problem ID', 'Result',
               'Memory', 'RunTime', 'Language', 'Length', 'Submit Time']

    for i in range(len(info)):
        if info[i].string != None:
            print("%s:%s" % (printLs[i], info[i].string))
    print('--------------------')

4.3运行并查看结果

爬虫程序的运行结果如图4-7所示,输入题目ID和语言在文件选择框中选择源代码文件后,会自动提交及返回评测结果,并在本地输出。
在这里插入图片描述

4.4本章小结

本章案例通过模拟网站登录并提交数据获取返回结果,介绍了Requests库,使用库函数发送GET 和 POST请求,并以请求实现模拟登录、提交等操作,然后通过 Requests的高级特性使用 session()方法维持会话,在爬虫实例中保持登录时的cookies以维持登录状态,以及使用 BeautifulSoup库结合网页抓包分析,解析并获取HTML 节点中需要的内容。上述的库、网页抓包分析元素、了解 base64编码在HTTP数据传输中的运用等都是爬虫的基础。
在这里插入图片描述

标签:请求,登录,Python,base64,爬取,session,提交,源代码,id
From: https://blog.csdn.net/andyyah/article/details/140974327

相关文章

  • Python爬虫案例与实战:爬取豆瓣电影简介
    Python爬虫案例与实战:爬取豆瓣电影简介本章案例将介绍如何爬取豆瓣电影简介,以此帮助读者学习如何通过编写爬虫程序来批量地从互联网中获取信息。本案例中将借助两个第三方库----Requests库和BeautifulSoup库。通过Requests库获取相关的网页信息,通过BeautifulSoup库解析大......
  • 趣味Python游戏编程:第3章 递归函数的威力:扫雷
    趣味Python游戏编程:第3章递归函数的威力:扫雷在第2章中,我们制作了一个拼图游戏,玩家通过鼠标操作图片块移动。本章设计一款扫雷游戏,玩法是在一个方块阵列中随机埋设一定数量的地雷,然后由玩家逐个打开方块,并以排除所有地雷为最终游戏目标。如果玩家打开的方块中有地雷,则游戏......
  • Python 依赖管理神器 Poetry 深入指南
    Poetry依赖管理详细教程引言在现代软件开发中,依赖管理是项目成功的关键。Python开发者现在有了一个新的选择:Poetry。Poetry是一个现代的Python包管理工具,旨在简化Python项目的创建、打包和发布。它提供了一种更直观和高效的方式来管理项目的依赖关系,相较于传统的p......
  • python的函数、魔法方法和案例
    1.python函数中self的用法在Python中,self 是一个对当前实例(对象)的引用,用于访问属于该类的变量和方法。在定义类的方法时,通常需要将 self 作为第一个参数。这允许在类的实例上调用方法时,自动将实例本身作为参数传递给方法。classPerson:def__init__(self,name......
  • 【视频讲解】Python灰色关联度分析直播带货效用、神经退行性疾病数据
    原文链接:https://tecdat.cn/?p=37273原文出处:拓端数据部落公众号 分析师:JiayiDeng 本文展示如何用灰色关联度分析的直播带货效用及作用机制研究,并结合一个分析神经退行性疾病数据实例的代码数据,为读者提供一套完整的实践数据分析流程。一、研究难点直播带货作为新兴产业,缺......
  • 线性方程组迭代算法的Python实现
    更多精彩,关注博客园主页,不断学习!不断进步!我的主页csdn很少看私信,有事请b站私信博客园主页-发文字笔记-常用有限元鹰的主页内容:ABAQUS数值模拟相关Python科学计算开源框架,编程学习笔记哔哩哔哩主页-发视频-常用FE-有限元鹰的个人空间内容:模拟案例网格划分游戏视频,......
  • 最小二乘法原理推导+代码实现[Python]
    0.前言本文主要介绍了最小二乘法公式推导,并且使用Python语言实现线性拟合。读者需要具备高等数学、线性代数、Python编程知识。请读者按照文章顺序阅读。绘图软件为:geogebra5。1.原理推导1.1应用最小二乘法在购房中的应用通常涉及房价预测和房屋定价方面。这种统计方法通......
  • python opencv图片简单操作
    一、从文件读取图片cv2.imread(filename,flags) 参数: filepath:读入image的完整路径 flags:标志位,{cv2.IMREAD_COLOR,cv2.IMREAD_GRAYSCALE,cv2.IMREAD_UNCHANGED} cv2.IMREAD_COLOR:默认参数,读入一副彩色图片,忽略alpha通道,可用1作为实参替代 cv2.IMREAD_GRAYSCALE:读入......
  • Python 中的排序与 ASCII 编码解析
    1.引言    不知道你有没有想过用Python进行一些排序的工作,对于一些数量比较小的数字集合(例如:1、15、32、79、6、55)我们可以迅速发现最大的79和最小的1,但当这个数量非常大的时候,我们找大小就很费劲了,而这种繁琐的工作就应该派计算机出马了2.比大小  a.常规数字比......
  • Python使用Memcached示例
    关注我,持续分享逻辑思维&管理思维&面试题;可提供大厂面试辅导、及定制化求职/在职/管理/架构辅导;推荐专栏《10天学会使用asp.net编程AI大模型》,目前已完成所有内容。一顿烧烤不到的费用,让人能紧跟时代的浪潮。从普通网站,到公众号、小程序,再到AI大模型网站。干货满满。学成后可......