使用U++的简单多请求Web爬网程序 完整的数控加工程序必须由
suiw9 2024-11-07 13:23 23 浏览 0 评论
本文使用的是U++框架。请参阅Ultimate++入门以获取有关环境的介绍。
U++框架提供了一个HttpRequest能够异步操作的类。在此示例中,我们将利用此功能使用多达60个并行HTTP连接来构造一个简单的单线程Web搜寻器。
设计GUI
我们将提供一个简单的GUI来显示抓取进度:
首先,我们将为我们的应用程序设计一个简单的GUI布局。在这里,GUI相当简单,但是使用布局设计器仍然值得考虑:
布局包含3ArrayCtrl个小部件,它们基本上是表格。我们将使用工作来显示单个HTTP请求的进度,完成以显示已结束的HTTP请求的结果,并从中获得乐趣和路径,这将为完成的任何行显示从种子url到完成的url的url的“路径”。
现在,让我们使用此布局并在代码中设置一些内容:
#define LAYOUTFILE <GuiWebCrawler/GuiWebCrawler.lay>
#include <CtrlCore/lay.h>
struct WebCrawler : public WithCrawlerLayout<TopWindow> {
WebCrawler();
};123456复制代码类型:[html]
WebCrawler将是我们应用程序的主要类别。#include在将设计的布局“导入”代码之前,这很奇怪,即它定义WithCrawlerLayout了代表我们布局的模板类。通过从中获取的,我们添加work,finished和pathArrayCtrl小部件为成员变量WebCrawler。我们将完成在WebCrawler构造函数中的设置:
WebCrawler::WebCrawler()
{
CtrlLayout(*this, "WebCrawler");
work.AddColumn("URL");
work.AddColumn("Status");
finished.AddColumn("Finished");
finished.AddColumn("Response");
finished.WhenCursor = [=] { ShowPath(); }; // when cursor is changed in finished,
// show the path
finished.WhenLeftDouble = [=] { OpenURL(finished); };
path.AddColumn("Path");
path.WhenLeftDouble = [=] { OpenURL(path); }; // double-click opens url in browser
total = 0;
Zoomable().Sizeable();
}123456789101112131415复制代码类型:[html]
CtrlLayout是WithCrawlerLayout将小部件放置到设计位置的方法。其余代码用列设置列表,并使用中的相应方法连接小部件上的一些用户操作WebCrawler(我们将在以后添加这些方法)。
资料模型
现在,有了无聊的GUI内容,我们将专注于有趣的部分-webcrawler代码。首先,我们将需要一些结构来跟踪事物:
struct WebCrawler : public WithCrawlerLayout<TopWindow> {
VectorMap<String, int> url; // maps url to the index of source url
BiVector<int> todo; // queue of url indices to process
struct Work { // processing record
HttpRequest http; // request
int urli; // url index
};
Array<Work> http; // work records
int64 total; // total bytes downloaded12345678910复制代码类型:[html]
VectorMap是一个独特的U++容器,可以将其视为数组和映射的组合。它提供了基于索引的键和值访问方式,以及一种快速找到键索引的方法。我们将使用url一种避免重复的url请求(将url放入密钥)的方法,并将'parent'url的索引作为值,以便以后可以显示种子url的路径。
接下来,我们要处理一系列的URL。从html提取网址时,我们会将其放入urlVectorMap。这意味着每个url在url中都有唯一的索引,因此我们只需要有索引队列todo。
最后,我们将需要一些缓冲区来保留并发请求。处理记录Work只需HttpRequest与url索引结合即可(只是知道我们要处理的url)。Array是U++容器,能够存储没有任何形式的副本的对象。
主循环
我们有数据模型,让我们开始编写代码。首先,让我们向用户询问种子网址:
void WebCrawler::Run()
{ // query the seed url, then do the show
String seed = "www.codeproject.com"; // predefined seed url
if(!EditText(seed, "GuiWebSpider", "Seed URL")) // query the seed url
return;
todo.AddTail(0); // first url to process index is 0
url.Add(seed, 0); // add to database1234567复制代码类型:[html]
Seed是第一个网址,因此我们知道它将具有index0。我们将简单地将其添加到url和中todo。现在真正的工作开始了:
Open(); // open the main window
while(IsOpen()) { // run until user closes the window
ProcessEvents(); // process GUI events123复制代码类型:[html]
我们将运行循环,直到用户关闭窗口。我们需要在此循环中处理GUI事件。循环的其余部分将处理实际内容:
while(todo.GetCount() && http.GetCount() < 60)
{ // we have something to do and have less than 60 active requests
int i = todo.Head(); // pop url index from the queue
todo.DropHead();
Work& w = http.Add(); // create a new http request
w.urli = i; // need to know source url index
w.http.Url(url.GetKey(i)) // setup request url
.UserAgent("Mozilla/5.0 (Windows NT 6.1; WOW64; rv:11.0)
Gecko/20100101 Firefox/11.0") // lie a little :)
.Timeout(0); // asynchronous mode
work.Add(url.GetKey(i)); // show processed URL in GUI
work.HeaderTab(0).SetText
(Format("URL (%d)", work.GetCount())); // update list header
}1234567891011121314复制代码类型:[html]
如果我们有东西todo并且少于60个并发请求,则添加一个新的并发请求。
下一步是处理所有活动的HTTP请求。HttpRequest类使用method来做到这一点Do。在非阻塞模式下,此方法尝试进行连接请求。我们需要做的就是为所有活动请求调用此方法,然后读取状态。
但是,即使可以在不等待“活动”模式下的实际套接字事件的情况下执行此操作,行为良好的程序也应首先等待,直到可以从套接字写入或读取套接字,以节省系统资源。U++SocketWaitEvent为此提供了确切的类:
SocketWaitEvent we; // we shall wait for something to happen to our request sockets
for(int i = 0; i < http.GetCount(); i++)
we.Add(http[i].http);
we.Wait(10); // wait at most 10ms (to keep GUI running)1234复制代码类型:[html]
唯一的问题是SocketWaitEvent仅在套接字上等待,我们可以运行GUI。我们通过将最大等待限制指定为10ms来解决此问题(我们知道目前至少会发生周期性的计时器事件,应由处理ProcessEvents)。
清除此问题后,我们可以继续处理请求:
int i = 0;
while(i < http.GetCount()) { // scan through active requests
Work& w = http[i];
w.http.Do(); // run request
String u = url.GetKey(w.urli); // get the url from index
int q = work.Find(u); // find line of url in GUI work list
if(w.http.InProgress()) { // request still in progress
if(q >= 0)
work.Set(q, 1, w.http.GetPhaseName()); // set GUI to inform user
// about request phase
i++;
}
else { // request finished
String html = w.http.GetContent(); // read request content
total += html.GetCount(); // just keep track about total content length
finished.Add(u, w.http.IsError() ? String().Cat() << w.http.GetErrorDesc()
: String().Cat() << w.http.GetStatusCode()
<< ' ' << w.http.GetReasonPhrase()
<< " (" << html.GetCount() << " bytes)",
w.urli); // GUI info about finished url status,
// with url index as last parameter
finished.HeaderTab(0).SetText(Format("Finished (%d)", finished.GetCount()));
finished.HeaderTab(1).SetText(Format("Response (%` KB)", total >> 10));
if(w.http.IsSuccess()) { // request ended OK
ExtractUrls(html, w.urli); // extact new urls
Title(AsString(url.GetCount()) + " URLs found"); // update window title
}
http.Remove(i); // remove from active requests
work.Remove(q); // remove from GUI list of active requests
}
}12345678910111213141516171819202122232425262728293031复制代码类型:[html]
这个循环看起来很复杂,但是大多数代码都用于更新GUI。HttpRequest类具有方便的GetPhaseName方法来描述请求中发生的事情。InProgress是true直到请求完成(作为成功或某种故障)。如果请求成功,我们将使用ExtractUrls新的url从html代码进行测试。
获取新的URL
为简单起见,这ExtractUrls是一个非常幼稚的实现,我们要做的就是扫描“http://”或“https://”字符串,然后读取下一个看起来像这样的字符url:
bool IsUrlChar(int c)
{// characters allowed
return c == ':' || c == '.' || IsAlNum(c) || c == '_' || c == '%' || c == '/';
}
void WebCrawler::ExtractUrls(const String& html, int srci)
{// extract urls from html text and add new urls to database, srci is source url
int q = 0;
while(q < html.GetCount()) {
int http = html.Find("http://", q); // .Find returns next position of pattern
int https = html.Find("https://", q); // or -1 if not found
q = min(http < 0 ? https : http, https < 0 ? http : https);
if(q < 0) // not found
return;
int b = q;
while(q < html.GetCount() && IsUrlChar(html[q]))
q++;
String u = html.Mid(b, q - b);
if(url.Find(u) < 0) { // do we know about this url?
todo.AddTail(url.GetCount()); // add its (future) index to todo
url.Add(u, srci); // add it to main url database
}
}
}123456789101112131415161718192021222324复制代码类型:[html]
我们把所有候选的URLurl,并todo通过主循环处理。
最后的润色
至此,所有的辛苦工作已经完成。其余代码只是两个便捷功能,其中一个在双击finished或path列出时打开url:
void WebCrawler::OpenURL(ArrayCtrl& a)
{
String u = a.GetKey(); // read url from GUI list
WriteClipboardText(u); // put it to clipboard
LaunchWebBrowser(u); // launch web browser
}123456复制代码类型:[html]
(我们也将URL作为奖励放置在剪贴板上。)
另一个函数填充path列表,以显示从种子URL到finished列表中URL的路径:
void WebCrawler::ShowPath()
{ // shows the path from seed url to finished url
path.Clear();
if(!finished.IsCursor())
return;
int i = finished.Get(2); // get the index of finished
Vector<String> p;
for(;;) {
p.Add(url.GetKey(i)); // add url index to list
if(i == 0) // seed url added
break;
i = url[i]; // get parent url index
}
for(int i = p.GetCount() - 1; i >= 0; i--) // display in reverted order, with seed first
path.Add(p[i]);
}12345678910111213141516复制代码类型:[html]
在这里,我们使用“双重性质”VectorMap使用索引从子网址遍历回到种子。
现在缺少的唯一一小段代码是MAIN:
GUI_APP_MAIN
{
WebCrawler().Run();
}1234复制代码类型:[html]
接下来,我们进行了大约150行的带有GUI的简单并行Web爬网程序。
相关推荐
- 10款超实用JavaScript音频库(js播放音频代码)
-
HTML5提供了一种新的音频标签实现和规范用一个简单的HTML对象而无需音频插件来控制音频。这只是一个简单的整合这些新的HTML5音频特征及使用JavaScript来创建各种播放控制。下面将介绍10款...
- PROFINET转Modbus网关——工业协议融合的智能枢纽
-
三格电子SG-PNh750-MOD-221,无缝连接Profinet与Modbus,赋能工业物联产品概述...
- 简单实用的Modbus类库,支持从站和DTU
-
一、简介...
- [西门子PLC] S7-200 SMART PROFINET :通过GSD组态PLC设备
-
从S7-200SMARTV2.5版本开始,S7-200SMART开始支持做PROFINETIO通信的智能设备。从而,两个S7-200SMART之间可以进行PROFINETI...
- Modbus(RTU / TCP)有什么异同(modbus tcp和tcp)
-
Modbus是一种广泛使用的工业自动化通信协议,它支持设备之间的数据交换。Modbus协议有两个主要的变体:ModbusRTU(二进制模式)和ModbusTCP(基于TCP/IP网络的模式)。尽管...
- Modbus通信调试步骤详解(modbus调试工具怎么用)
-
Modbus通信调试步骤详解 Modbus通信分为串口和以太网,无论是串口还是以太网,只要是标准Modbus,就可以用Modbus模拟器进行调试。按以下几步进行调试。...
- 理解Intel手册汇编指令(intel 汇编指令手册)
-
指令格式...
- 「西门子PLC」S7-200 SMART的Modbus RTU通讯
-
S7-200SMART集成的RS485端口(端口0)以及SBCM01RS485/232信号板(端口1)两个通信端口可以同时做MODBUSRTU主站,或者一个做MODBUSRTU主站一个做MO...
- InfiniBand网络运维全指南:从驱动安装到故障排查
-
一、InfiniBand网络概述InfiniBand(直译为“无限带宽”技术,缩写为IB)是一种用于高性能计算的计算机网络通信标准,具有极高的吞吐量和极低的延迟,用于计算机与计算机之间的数据互连。它...
- 一加回归 OPPO,背后的秘密不可告人
-
有这样一个手机品牌,它诞生于互联网品牌。在大众群体看来,它的身世似乎模糊不清,许多人以为它是国外品牌。它的产品定位是极客群体,深受国内发烧友,甚至国外极客玩家喜爱。...
- [西门子PLC] S7-200SMART快速高效的完成Modbus通信程序的设计
-
一、导读Modbus通信是一种被广泛应用的通信协议,在变频器、智能仪表还有其他一些智能设备上都能见到它的身影。本文呢,就把S7-200SMART系列PLC当作Modbus主站,把...
- 狂肝10个月手搓GPU,他们在我的世界中玩起我的世界,梦想成真
-
梦晨衡宇萧箫发自凹非寺量子位|公众号QbitAI自从有人在《我的世界》里用红石电路造出CPU,就流传着一个梗:...
- [西门子PLC] 博途TIA portal SCL编程基础入门:1-点动与自锁
-
一、S7-SCL编程语言简介...
- 工作原理系列之:Modbus(modbus工作过程)
-
MODBUS是一种在自动化工业中广泛应用的高速串行通信协议。该协议是由Modion公司(现在由施耐德电气公司获得)于1979年为自己的可编程逻辑控制器开发的。该协议充当了PLCS和智能自动化设备之间的...
你 发表评论:
欢迎- 一周热门
-
-
Linux:Ubuntu22.04上安装python3.11,简单易上手
-
宝马阿布达比分公司推出独特M4升级套件,整套升级约在20万
-
MATLAB中图片保存的五种方法(一)(matlab中保存图片命令)
-
别再傻傻搞不清楚Workstation Player和Workstation Pro的区别了
-
Linux上使用tinyproxy快速搭建HTTP/HTTPS代理器
-
如何提取、修改、强刷A卡bios a卡刷bios工具
-
Element Plus 的 Dialog 组件实现点击遮罩层不关闭对话框
-
MacOS + AList + 访达,让各种云盘挂载到本地(建议收藏)
-
日本组合“岚”将于2020年12月31日停止团体活动
-
SpringCloud OpenFeign 使用 okhttp 发送 HTTP 请求与 HTTP/2 探索
-
- 最近发表
-
- 10款超实用JavaScript音频库(js播放音频代码)
- Howler.js,一款神奇的 JavaScript 开源网络音频工具库
- PROFINET转Modbus网关——工业协议融合的智能枢纽
- 简单实用的Modbus类库,支持从站和DTU
- [西门子PLC] S7-200 SMART PROFINET :通过GSD组态PLC设备
- Modbus(RTU / TCP)有什么异同(modbus tcp和tcp)
- Modbus通信调试步骤详解(modbus调试工具怎么用)
- 理解Intel手册汇编指令(intel 汇编指令手册)
- 「西门子PLC」S7-200 SMART的Modbus RTU通讯
- InfiniBand网络运维全指南:从驱动安装到故障排查
- 标签列表
-
- dialog.js (57)
- importnew (44)
- windows93网页版 (44)
- yii2框架的优缺点 (45)
- tinyeditor (45)
- qt5.5 (60)
- windowsserver2016镜像下载 (52)
- okhttputils (51)
- android-gif-drawable (53)
- 时间轴插件 (56)
- docker systemd (65)
- slider.js (47)
- android webview缓存 (46)
- pagination.js (59)
- loadjs (62)
- openssl1.0.2 (48)
- velocity模板引擎 (48)
- pcre library (47)
- zabbix微信报警脚本 (63)
- jnetpcap (49)
- pdfrenderer (43)
- fastutil (48)
- uinavigationcontroller (53)
- bitbucket.org (44)
- python websocket-client (47)