当前位置: 首页 > news >正文

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

启动时等待验证码.

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

处理完成后,显示数据

实现原理:利用已有的账号和密码登录后产生的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位的时间戳,它是给服务器用来校验请求的时间是否在合法范围内.知道它是什么,要做一个就简单了

下面是完整的程序代码:

复制代码

typeTForm1 = 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)protectedprocedure Execute; override;end;varForm1: TForm1;implementationusesDateUtils;{$R *.dfm}// 取13位数字时间
function GetDigitalTime: string;
varS_Char: string;
beginS_Char := FormatSettings.DateSeparator;Result := IntToStr(MilliSecondsBetween(IncHour(now, -8), StrToDateTime('1970'+ S_Char + '1' + S_Char + '1')));
end;procedure LoadTxtToCxGrid();   //把处理好的数据,加载进表格,展示给用户
beginvar Lines := TStringList.Create;tryLines.LoadFromFile('d:\resule.txt', TEncoding.UTF8);var view := form1.cxGrid1TableView1.DataController;for var i := 1 to Lines.Count - 1 dobeginvar k := view.AppendRecord;var arr: TArray<string> := Lines[i].Split([',']);for var j := 0 to 4 dobeginview.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;finallyLines.Free;DeleteFile('D:\123.txt');        //删除文件DeleteFile('d:\resule.txt');     //删除文件end;
end;function washData(): Boolean;  //清洗数据
varReader: TStreamReader;Writer: TStreamWriter;txts: string;JSONObj: TJSONObject;StockValue, GoodsNameValue: string;JsonArray: TJSONArray;
beginReader := TStreamReader.Create('D:\123.txt');Writer := TStreamWriter.Create('D:\resule.txt');trytxts := Reader.ReadToEnd; // 读取全部的文件内容JSONObj := TJSONObject.ParseJSONValue(txts) as TJSONObject;tryif Assigned(JSONObj) thenbeginJsonArray := JSONObj.GetValue('rows') as TJSONArray;    //选对节点,才能拿到正确数据Writer.WriteLine('物料代码,物料名称,规格型号,单位,库存');for var i := 0 to JsonArray.Count - 1 dobeginStockValue := JsonArray.Items[i].GetValue<string>('stock'); // 获取 stock 字段值GoodsNameValue := JsonArray.Items[i].GetValue<string>('goods_name'); // 获取 goods_name 字段值// 输出数据if GoodsNameValue <> '' thenbeginGoodsNameValue := 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;finallyJSONObj.Free;end;finallyReader.Free;Writer.Free;//写入表格LoadTxtToCxGrid;end;
end;procedure TForm1.scGPEdit1KeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
beginif Key = 13 thenscGPEdit1RightButtonClick(Sender);
end;procedure TForm1.scGPEdit1RightButtonClick(Sender: TObject);
varss_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 // 初步判断用户输入的验证码长度是否正确beginShowMessage('请输入正确的验证码');Exit;end;// --------获取token  ---------Resp := NetHTTPClient1.Get(TokenURL); // 取得登陆页面的源代码// -------用正则取出tokenmatch := TRegEx.match(Resp.ContentAsString(TEncoding.UTF8), '[\w]{32}');if match.Success thenbegintoken := match.Groups[0].Value;endelsebeginShowMessage('没有找到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  //如果登陆成功,则开始抓包beginSleep(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中的内容为需要的格式endelseShowMessage('请求失败');
end;
//初始化窗口.开始时只显示验证码部分
procedure TForm1.FormCreate(Sender: TObject);
beginscGPPanel2.Visible := false;Self.Height := 120;scGPEdit1.Text := '请等待...';scGPEdit1.Enabled := False;Image1Click(Sender);
end;procedure TForm1.Image1Click(Sender: TObject); // 点击图片时更新验证码
varMyThread: TMyThread;
begin// 创建并启动自定义线程MyThread := TMyThread.Create(true);MyThread.FreeOnTerminate := true; // 线程执行结束后自动释放MyThread.Start;
end;{ TMyThread }
procedure TMyThread.Execute;
varStream: TMemoryStream;pngimage: TPngImage;
beginStream := 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 thenShowMessage('验证码加载失败,请点击右边的图片重新加载')elsebeginForm1.scGPEdit1.Enabled := true;Form1.scGPEdit1.text := '';end;finallypngimage.Free;Stream.Free;end;
end;end.

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 消息队列:Kafka吞吐量为什么比RocketMQ大
  • 3.特征工程-特征抽取、特征预处理、特征降维
  • 第一阶段面试问题(后半部分)
  • java之IO篇——File、字节流、字符流
  • 【IO】使用有名管道实现,一个进程用于给另一个进程发消息,另一个进程收到消息后,展示到终端上,并且将消息保存到文件上一份
  • 新书速览|AI创意商业广告设计:Adobe Firefly + Photoshop
  • 现代前端架构介绍(第一部分):App是如何由不同的构建块构成的
  • 数据中台建设之数据汇聚与数据交换
  • Apache Pig: 高级数据处理平台
  • 【开源】嵌入式Linux(IMX6U)应用层综合项目(1)--云平台调试APP
  • 网络流算法:最大流问题
  • SparkSQL---编程模型的操作,数据加载与落地及自定义函数的使用
  • 最新全国各省市水系矢量数据(2024年更新)
  • 【教学类-73-02】20240805广口瓶(宽口瓶)02
  • 类和对象——日期类实现
  • $translatePartialLoader加载失败及解决方式
  • 2017 年终总结 —— 在路上
  • Debian下无root权限使用Python访问Oracle
  • JavaWeb(学习笔记二)
  • Java比较器对数组,集合排序
  • nfs客户端进程变D,延伸linux的lock
  • XForms - 更强大的Form
  • 翻译--Thinking in React
  • 罗辑思维在全链路压测方面的实践和工作笔记
  • 如何使用 OAuth 2.0 将 LinkedIn 集成入 iOS 应用
  • 一些关于Rust在2019年的思考
  • 浅谈sql中的in与not in,exists与not exists的区别
  • ​【经验分享】微机原理、指令判断、判断指令是否正确判断指令是否正确​
  • ​插件化DPI在商用WIFI中的价值
  • ​软考-高级-信息系统项目管理师教程 第四版【第14章-项目沟通管理-思维导图】​
  • # Kafka_深入探秘者(2):kafka 生产者
  • #ubuntu# #git# repository git config --global --add safe.directory
  • #微信小程序(布局、渲染层基础知识)
  • (20)目标检测算法之YOLOv5计算预选框、详解anchor计算
  • (3)llvm ir转换过程
  • (C语言)fgets与fputs函数详解
  • (二)hibernate配置管理
  • (附源码)python旅游推荐系统 毕业设计 250623
  • (附源码)计算机毕业设计SSM疫情居家隔离服务系统
  • (汇总)os模块以及shutil模块对文件的操作
  • (亲测有效)推荐2024最新的免费漫画软件app,无广告,聚合全网资源!
  • (算法)硬币问题
  • (五)MySQL的备份及恢复
  • (原創) 如何動態建立二維陣列(多維陣列)? (.NET) (C#)
  • (转)scrum常见工具列表
  • (转)Unity3DUnity3D在android下调试
  • (轉)JSON.stringify 语法实例讲解
  • (轉貼) 資訊相關科系畢業的學生,未來會是什麼樣子?(Misc)
  • ..回顾17,展望18
  • .net 4.0 A potentially dangerous Request.Form value was detected from the client 的解决方案
  • .Net(C#)自定义WinForm控件之小结篇
  • .net对接阿里云CSB服务
  • .NET企业级应用架构设计系列之结尾篇
  • .NET运行机制
  • [04]Web前端进阶—JS伪数组