delphi 12 学习如何登陆网站下载文件

news2024/9/21 1:31:04

启动时等待验证码.

输入验证码后,等待处理数据

处理完成后,显示数据

实现原理:利用已有的账号和密码登录后产生的cookie,向服务器请求数据.返回的数据是JSON格式,后期需要自己整理.

注意,请在程序中使用同一个TnetHttpClient控件来完成.因为里面保存了cookie信息

需要了解的知识点:

一. token:

在 Web 开发中,Token 经常用于用户身份验证。当用户成功登录后,服务器会生成一个 Token,并将其返回给客户端。客户端将该 Token 存储在本地,以后的请求都携带该 Token,用于证明请求的合法性。服务器会根据 Token 验证用户身份,并决定是否允许该请求访问相关资源。

在登录页面的源代码中,按 ctrl+F 查找 token

二.cookie

复制代码

Cookie 主要用于跟踪用户的状态和行为,以提供个性化的用户体验。通过存储在 Cookie 中的数据,网站可以识别和区分不同的用户,记录用户的偏好设置,保持用户登录状态,以及追踪用户在网站上的访问轨迹等。这些信息可以在用户下次访问网站时被读取并使用。

Cookie 有两种类型:会话性 Cookie 和持久性 Cookie。

会话性 Cookie 存储在用户的计算机上,但在用户关闭浏览器时会被自动删除。这种类型的 Cookie 通常用于临时存储会话信息,如用户的登录状态。

持久性 Cookie 有一个指定的过期日期,可以在用户关闭浏览器后继续存在。这种类型的 Cookie 可以用于记住用户的偏好设置和提供个性化的内容。

复制代码

三.Referer 

Referer 是一个 HTTP 请求头字段,提供了当前请求的来源信息,用于统计、安全验证和针对性处理等用途。但由于用户隐私的考虑,Referer 值可能为空或被限制。

四.数据的请求地址.就是向服务器请求数据的地址.

下面的动画中,展示了登录网站后,如何获取Referer和数据请求地址的过程.

第一步就是登陆了,

第二步是转到要下载文件的页面,按F12调出开发者工具.红3是清除当前记录,避免干扰

 第三步.点击下载文件,然后会看到出现两条记录(以我当面的页面为例).我们观察第二个地址.里面有limit,明显是分页的,舍去,取第一个地址.

也就是数据请求的地址找到了. 等于号后面的那串13位数字,我后面会讲

第四步,单击第一条记录,可以看到它的标头信息,里面就有Referer 信息,记下来.其实为了保险起见,标头里的信息应该全部封装到代码里才算完美.

 点击预览选项卡,这里你就可以看到你的数据包了,我们要抓的,就是这个数据. 

 最后我们再回头看看这一串13位的数字.它其实是一个13位的时间戳,它是给服务器用来校验请求的时间是否在合法范围内.知道它是什么,要做一个就简单了

下面是完整的程序代码:

复制代码

type
  TForm1 = class(TForm)
    Image1: TImage;
    Label1: TLabel;
    NetHTTPClient1: TNetHTTPClient;
    scGPEdit1: TscGPEdit;
    cxGrid1Level1: TcxGridLevel;
    cxGrid1: TcxGrid;
    cxGrid1TableView1: TcxGridTableView;
    cxGrid1TableView1Column1: TcxGridColumn;
    cxGrid1TableView1Column2: TcxGridColumn;
    cxGrid1TableView1Column3: TcxGridColumn;
    cxGrid1TableView1Column4: TcxGridColumn;
    cxGrid1TableView1Column5: TcxGridColumn;
    scGPPanel1: TscGPPanel;
    scGPPanel2: TscGPPanel;
    procedure FormCreate(Sender: TObject);
    procedure Image1Click(Sender: TObject);
    procedure scGPEdit1RightButtonClick(Sender: TObject);
    procedure scGPEdit1KeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

  TMyThread = class(TThread)
  protected
    procedure Execute; override;
  end;

var
  Form1: TForm1;

implementation

uses
  DateUtils;

{$R *.dfm}

// 取13位数字时间
function GetDigitalTime: string;
var
  S_Char: string;
begin
  S_Char := FormatSettings.DateSeparator;
  Result := IntToStr(MilliSecondsBetween(IncHour(now, -8), StrToDateTime('1970'
    + S_Char + '1' + S_Char + '1')));
end;

procedure LoadTxtToCxGrid();   //把处理好的数据,加载进表格,展示给用户
begin
  var Lines := TStringList.Create;
  try
    Lines.LoadFromFile('d:\resule.txt', TEncoding.UTF8);
    var view := form1.cxGrid1TableView1.DataController;

    for var i := 1 to Lines.Count - 1 do
    begin
      var k := view.AppendRecord;
      var arr: TArray<string> := Lines[i].Split([',']);
      for var j := 0 to 4 do
      begin
        view.Values[k, j] := arr[j];  //这里一定要注意.先在cxgrid中创建好列,这里是五列,所以才写了0 to 4 .群里有个老六,就为这点喷我,搞得很不愉快.
      end;
    end;
    //隐藏验证码部分,显示出数据表
    Form1.scGPPanel1.Visible := False;
    Form1.Height := 300;
    Form1.scGPPanel2.Visible := True;
    Form1.scGPPanel2.Align := alClient;
  finally
    Lines.Free;
    DeleteFile('D:\123.txt');        //删除文件
    DeleteFile('d:\resule.txt');     //删除文件
  end;
end;

function washData(): Boolean;  //清洗数据
var
  Reader: TStreamReader;
  Writer: TStreamWriter;
  txts: string;
  JSONObj: TJSONObject;
  StockValue, GoodsNameValue: string;
  JsonArray: TJSONArray;
begin
  Reader := TStreamReader.Create('D:\123.txt');
  Writer := TStreamWriter.Create('D:\resule.txt');
  try
    txts := Reader.ReadToEnd; // 读取全部的文件内容

    JSONObj := TJSONObject.ParseJSONValue(txts) as TJSONObject;
    try
      if Assigned(JSONObj) then
      begin
        JsonArray := JSONObj.GetValue('rows') as TJSONArray;    //选对节点,才能拿到正确数据
        Writer.WriteLine('物料代码,物料名称,规格型号,单位,库存');
        for var i := 0 to JsonArray.Count - 1 do
        begin
          StockValue := JsonArray.Items[i].GetValue<string>('stock'); // 获取 stock 字段值
          GoodsNameValue := JsonArray.Items[i].GetValue<string>('goods_name'); // 获取 goods_name 字段值

          // 输出数据
          if GoodsNameValue <> '' then
          begin
            GoodsNameValue := GoodsNameValue.Replace('\', '', [rfReplaceAll]);  //去掉所有'\'
            GoodsNameValue := GoodsNameValue.Replace('刀', '刀/', [rfReplaceAll]);
            GoodsNameValue := GoodsNameValue.Replace('丝锥', '丝锥/', [rfReplaceAll]);
            GoodsNameValue := GoodsNameValue.Replace('钻D', '钻/D', [rfReplaceAll]);
            GoodsNameValue := GoodsNameValue.Replace('钻头', '钻头/', [rfReplaceAll]);
            var arr: tarray<string>;
            arr := GoodsNameValue.Split(['/']);
            Writer.WriteLine(arr[0] + ',' + arr[1] + ',' + arr[2] + ',' + arr[3]
              + ',' + StockValue);
          end;
        end;
      end;
    finally
      JSONObj.Free;
    end;
  finally
    Reader.Free;
    Writer.Free;
    //写入表格
    LoadTxtToCxGrid;
  end;
end;

procedure TForm1.scGPEdit1KeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
begin
  if Key = 13 then
    scGPEdit1RightButtonClick(Sender);
end;

procedure TForm1.scGPEdit1RightButtonClick(Sender: TObject);
var
  ss_Request: TStringList;
  token: string;
  captcha: string;
  match: TMatch;
  S2, S3: TMemoryStream;
  Resp: IHTTPResponse;
const
  // 登陆页面
  TokenURL = '登陆地址';
  // 提交网址
  PostURL = '登陆地址';
begin
 //封装标头信息
  NetHTTPClient1.UserAgent :=
    'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36';
  NetHTTPClient1.Accept := 'application/json, text/javascript, */*; q=0.01';
  NetHTTPClient1.ContentType := 'application/json';

  captcha := Trim(scGPEdit1.text); // 用户输入的验证码
  if Length(captcha) <> 4 then // 初步判断用户输入的验证码长度是否正确
  begin
    ShowMessage('请输入正确的验证码');
    Exit;
  end;

  // --------获取token  ---------
  Resp := NetHTTPClient1.Get(TokenURL); // 取得登陆页面的源代码
  // -------用正则取出token
  match := TRegEx.match(Resp.ContentAsString(TEncoding.UTF8), '[\w]{32}');
  if match.Success then
  begin
    token := match.Groups[0].Value;
  end
  else
  begin
    ShowMessage('没有找到token');
    Exit;
  end;

  // --------封包---------
  ss_Request := TStringList.Create;
  ss_Request.Add('__token__=' + token);
  ss_Request.Add('username=登陆的用户名');
  ss_Request.Add('password=登陆密码');
  ss_Request.Add('captcha=' + scgpedit1.text);  //scgpedit1.text 是验证码,这个需要手动输入
  // resp 提交登陆请求
  Resp := NetHTTPClient1.Post(PostURL, ss_Request);

  if Resp.StatusCode = 200 then  //如果登陆成功,则开始抓包
  begin
    Sleep(500);
    NetHTTPClient1.CustomHeaders['X-Requested-With'] := 'XMLHttpRequest';
    NetHTTPClient1.CustomHeaders['Referer'] :=  'xxxx';

    S2 := TMemoryStream.Create;
    NetHTTPClient1.Get('数据请求的地址'+ GetDigitalTime, S2);
    S2.Position := 0;
    S2.SaveToFile('d:\123.txt');    //把流数据保存成文件,以便后期处理
    scGPEdit1.text := '稍等,处理中...';
    scGPEdit1.Enabled := false;
    washData;    //自定义函数,整理123.txt中的内容为需要的格式
  end
  else
    ShowMessage('请求失败');
end;
//初始化窗口.开始时只显示验证码部分
procedure TForm1.FormCreate(Sender: TObject);
begin
  scGPPanel2.Visible := false;
  Self.Height := 120;
  scGPEdit1.Text := '请等待...';
  scGPEdit1.Enabled := False;
  Image1Click(Sender);
end;

procedure TForm1.Image1Click(Sender: TObject); // 点击图片时更新验证码
var
  MyThread: TMyThread;
begin
  // 创建并启动自定义线程
  MyThread := TMyThread.Create(true);
  MyThread.FreeOnTerminate := true; // 线程执行结束后自动释放
  MyThread.Start;
end;

{ TMyThread }
procedure TMyThread.Execute;
var
  Stream: TMemoryStream;
  pngimage: TPngImage;
begin
  Stream := TMemoryStream.Create;
  pngimage := TPngImage.Create;
  try   
    Form1.NetHTTPClient1.Get('验证码地址',  Stream);     // 下载验证码
    Stream.Position := 0;    //初始化读写位置
    pngimage.LoadFromStream(Stream); // 转换流
    Form1.Image1.Picture.Bitmap.Assign(pngimage); // 把验证码显示出来
    if Form1.Image1.Picture.Bitmap = nil then
      ShowMessage('验证码加载失败,请点击右边的图片重新加载')
    else
    begin
      Form1.scGPEdit1.Enabled := true;
      Form1.scGPEdit1.text := '';
    end;
  finally
    pngimage.Free;
    Stream.Free;
  end;
end;

end.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1974869.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C#编写软件发布公告1——客户端

前言 软件或者生活中有时需要将信息同步至电子公告板上&#xff0c;利用C#可以快速实现这一目的&#xff0c;这里以软件公告场景设计&#xff0c;主要是将软件的版本号等相关信息同步至服务器&#xff0c;同步成功后&#xff0c;任务需要查找的人员只要有Web浏览器就可以快速查…

用前所未有的方式体验我们的现代 API 文档

增强您的 API 文档 对于开发人员 为内部和外部消费者创建从 API 定义文件自动生成的精美 API 文档。 只需 4 个简单步骤即可编写 API 文档 API 采用的成功取决于 API 文档的质量。 Baklib 从您的 API 定义文件创建漂亮的&#xff08;完全可定制的&#xff09;API 文档。帮助…

4个自定义倒计时

<!DOCTYPE html> <html lang"zh-CN"><head><meta charset"UTF-8"><title>4个自定义倒计时</title><style>* {margin: 0;padding: 0;box-sizing: border-box;user-select: none;body {background: #0b1b2c;}}hea…

DedeCms 织梦系统 漏洞 上传webshell复现 四种方法 超详细

DedeCMS是织梦团队开发PHP 网站管理系统&#xff0c;它以简单、易用、高效为特色&#xff0c;组建出各种各样各具特色的网站&#xff0c;如地方门户、行业门户、政府及企事业站点等。 目录 方法一 &#xff1a;通过⽂件管理器上传WebShell 方法二&#xff1a;修改模板⽂件拿…

邻接矩阵实现图的存储

目录 一. 前言 二. 用邻接矩阵来实现图的存储 一. 前言 1. 图的定义 所谓图就是包含顶点和边的集合&#xff0c;是一种多对多的关系。用符号表示为&#xff1a;G(V,E)。其中&#xff0c;V代表顶点&#xff08;数据元素&#xff09;的有穷非空集合&#xff0c;E代表边的有穷集…

AI4-PPOCRLabel安装

推荐环境&#xff1a; - PaddlePaddle > 2.1.2 - Python 3.7 - CUDA10.1 / CUDA10.2 - CUDNN 7.6 1、安装Anaconda 说明&#xff1a;使用paddlepaddle需要先安装python环境&#xff0c;这里我们选择python集成环境Anaconda工具包 Anaconda是1个常用的python包管理程序 安装完…

虚拟机连接xshell的三种方式

第一 桥接 改为输入 systemctl restart network 关闭自启动防火墙 systemctl stop firewalld systemctl disable firewalld 查看本机网络信息 ifconfig 连接xshell 第二 nat 第三 仅主机

探索 Electron:打造深度书籍挖掘机的搜索体验

Electron是一个开源的桌面应用程序开发框架&#xff0c;它允许开发者使用Web技术&#xff08;如 HTML、CSS 和 JavaScript&#xff09;构建跨平台的桌面应用程序&#xff0c;它的出现极大地简化了桌面应用程序的开发流程&#xff0c;让更多的开发者能够利用已有的 Web 开发技能…

react-native从入门到实战系列教程-React Native Elements

react-native的ui框架内网真的是屈指可数&#xff0c;能用的成熟的几乎找不到。不像web端的繁荣景象&#xff0c;可以用荒凉来形容不为过。 京东的nutui说也支持react-native,官网及其简陋。尝试了未成功运行&#xff0c;可能是项目类型不同&#xff0c;对比其他类型的ui库都分…

centos安装es、kibana、ik

这里es使用的是7.10.2版本的es&#xff0c;物料包下载地址如下 #注意安装的插件需和es版本保持一致 #es https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-7.10.2-linux-x86_64.tar.gz #kibana https://artifacts.elastic.co/downloads/kibana/kibana-7.10…

phpMyAdmin之CMS靶场

方法一&#xff1a;通过日志文件拿webshell 常用的语句如下&#xff1a; show global variables like %general%; set global general_logon; set global general_log_file D:/phpStudy_pro/WWW/muma.php; show global variables like %general%; select <?php eval($_…

广西南宁高校大学智能制造实验室数字孪生可视化系统平台建设项目验收

南宁高校大学智能制造实验室&#xff0c;作为该地区乃至全国智能制造领域的重要研究和教学基地&#xff0c;一直致力于探索和创新智能制造技术。近日&#xff0c;该实验室的数字孪生可视化系统平台建设项目成功通过了验收&#xff0c;标志着其在数字孪生技术领域取得了重大突破…

c语言排序(2)

前言 在上一篇文章&#xff0c;我们学习了插入排序&#xff0c;选择排序以及交换排序中的冒泡排序&#xff0c;接下来我们继续学习交换排序、归并排序以及非比较排序。 1. 快速排序 快速排序是交换排序的一种&#xff0c;它的基本思想&#xff1a;任取待排序序列中的某元素作…

z3基础学习

z3基础学习 ​ z3是一个微软出品的开源约束求解器&#xff0c;能够解决很多种情况下的给定部分约束条件寻求一组满足条件的解的问题。 安装&#xff1a;pip install z3-solver 1. 简单使用 from z3 import * x Int(x) #创建名为x的int类型变量 y Int(y) solve(x y10,2*x…

【Verilog-CBB】开发与验证(1)——开个头

在Verilog代码设计的过程中&#xff0c;经常会涉及到一些常用组件的应用&#xff0c;比如仲裁器、打拍器、RS双向打拍器等。这些组件如果重复开发就会降低效率。这些常用的组件业内称为CBB&#xff08;Common Building Block&#xff09;。本专栏旨在开发一些好用易用的CBB&…

前端拥抱AI:LangChain.js 入门遇山开路之PromptTemplate

PromptTemplate是什么 PromptTemplate是一个可重复使用的模板&#xff0c;用于生成引导模型生成特定输出的文本。与Prompt的区别: PromptTemplate相对于普通Prompt的优势&#xff0c;即其灵活性和可定制性。 简单了解PromptTemplate后&#xff0c;咱们就来聊聊LangChain里的P…

Linux配置FTP服务

一、FTP服务基本信息 FTP服务器&#xff1a;一种应用广泛且古老的互联网文件传输协议&#xff0c;主要用于文件的双向传输。 默认端口号&#xff1a;21 全称&#xff1a;vsftpd 二、搭建FTP服务 1.关闭防火墙和selinux&#xff08;若linux系统没有这两种功能&#xff0c;跳…

最大化性能:VPS 主机优化技巧

如何让您的VPS更高效。VPS(虚拟专用服务器)是扩展网站具备成本效益的托管选项之一&#xff0c;虽然整体性能不错&#xff0c;但大多数用户并不知道&#xff0c;一些基本的优化&#xff0c;例如更改默认设置和降低负载&#xff0c;可能会大大提高其网站的速度。本文将为您介绍一…

阿里云ossbrowser安装及使用

ossbrowser是阿里云官方提供的OSS图形化管理工具&#xff0c;提供类似Windows资源管理器的功能。 阿里云对象存储OSS&#xff08;Object Storage Service&#xff09;是一款海量、安全、低成本、高可靠的云存储服务&#xff0c;可提供99.9999999999%&#xff08;12个9&#xf…

运放开环增益,闭环增益,增益带宽积与频率的关系。压摆率对输出信号影响,TINA仿真验证

开环增益 运放开环增益AOL&#xff0c;运放负反馈形成固定放大倍数的闭环增益&#xff0c;形成的条件是建立在AOL无穷大”的基础之上&#xff0c;实际运放的AOL并不是无穷大&#xff0c;是和频率有关系的。 当AOL不是无穷大时候&#xff0c;虚短是不成立的。并且当AOL比较小的时…