【问题标题】:When Web Browsing from code, how do you send information to an <input .* type="Submit"> and retrieve the resulting link?从代码浏览网页时,如何将信息发送到 <input .* type="Submit"> 并检索结果链接?
【发布时间】:2012-01-20 15:54:04
【问题描述】:

类似的线程可能是:

How do I programmatically send information to a web service in C# with .Net?
Maintain button submit value when using link to submit a form
Looking how to send multiple values with an input type=submit form
How send a form with Javascript when input name is "submit"?
How do you submit a form with javascript with an < input type="button">

...以上所有内容似乎几乎都回答了这个问题...但我完全被迷惑了。我认为类似于“Net.Post(something)”的东西是如何完成的……但我不确定。

我目前正在使用 F#,并且我已经弄清楚了如何解析链接。我还想出了如何使用正则表达式捕捉各种搜索栏和提交按钮。
我想使用我的代码专门通过以下方式在搜索引擎上搜索内容:

首先,获取HTML

第二,为各种按钮、文本栏和链接抓取 HTML

第三,使用一些未知的方法/设备/工具/功能将搜索线程发送到文本框...

第四,模拟鼠标点击网站上出现的提交“按钮”...

...

然后,在收到服务器的响应后,从下一个站点提取 HTML。
这是我的链接代码:

    type Url(x:string)=  
     member this.Tostring  = sprintf "%A" x
     member this.Request   = System.Net.WebRequest.Create(x)
     member this.Response  = this.Request.GetResponse()
     member this.Stream    = this.Response.GetResponseStream()
     member this.Reader    = new System.IO.StreamReader(this.Stream)
     member this.Html      = this.Reader.ReadToEnd()   
    let linkex                = "href=\s*\"[^\"h]*(http://[^&\"]*)\"" 

    let getLinks (txt:string) = [for m in Regex.Matches(txt,linkex)  
                                  -> m.Groups.Item(1).Value        ] 

    let collectLinks (url:Url) =   url.html 
                                |> getLinks

...我知道如何抓取搜索框字符串等等...问题是,当我去 google.com 并以与抓取链接相同的方式抓取搜索栏时,更新值带有我的搜索字符串的字段,然后我如何将更新的搜索栏提交到谷歌的服务器?

其次,如果我想更新它然后模拟鼠标点击,我该怎么做?

换句话说,我想以用户与网站交互的方式与网站交互。

【问题讨论】:

    标签: c# javascript .net f# browser


    【解决方案1】:

    基本上有两种选择 - 一些网页使用 HTTP GET 接受数据(这意味着数据作为 URL 的一部分发送)和其他使用 HTTP POST(这意味着数据作为请求的主体发送)。

    如果您使用的是 Google,那么您可以使用 HTTP GET 并将查询字符串放在 URL 中。例如,您可以只下载具有以下 URL 的网页:https://www.google.com/search?q=hello。因此,您需要做的就是生成如下 URL:

    let search = sprintf "http://www.google.com/search?q=%s"
    

    如果您想从 F# 发送 HTTP POST 请求,那么您需要创建一个请求,其正文包含编码表单中的表单值。这可以写成:

    open System.Text
    open System.IO
    open System.Net
    
    // URL of a simple page that takes two HTTP POST parameters. See the
    // form that submits there: http://www.snee.com/xml/crud/posttest.html
    let url = "http://www.snee.com/xml/crud/posttest.cgi"
    
    // Create & configure HTTP web request
    let req = HttpWebRequest.Create(url) :?> HttpWebRequest 
    req.ProtocolVersion <- HttpVersion.Version10
    req.Method <- "POST"
    
    // Encode body with POST data as array of bytes
    let postBytes = Encoding.ASCII.GetBytes("fname=Tomas&lname=Petricek")
    req.ContentType <- "application/x-www-form-urlencoded";
    req.ContentLength <- int64 postBytes.Length
    // Write data to the request
    let reqStream = req.GetRequestStream() 
    reqStream.Write(postBytes, 0, postBytes.Length);
    reqStream.Close()
    
    // Obtain response and download the resulting page 
    // (The sample contains the first & last name from POST data)
    let resp = req.GetResponse() 
    let stream = resp.GetResponseStream() 
    let reader = new StreamReader(stream) 
    let html = reader.ReadToEnd()
    

    除此之外,您在每一步都使用typemember 有点奇怪。每次访问成员时都会重新执行成员,因此您编写的代码非常不确定。您应该改用let 绑定。

    【讨论】:

    • 嗯,使用成员也是有问题的,因为您没有正确关闭请求和实现IDisposable 的其他对象。为了简单起见,我在 sn-p 中也没有这样做,但实际上应该这样做。在普通代码中,这很容易——只需使用use 而不是let,但是对成员这样做会非常困难。我不明白您为什么选择为此使用type。也许有一种方法可以更优雅地解决您试图解决的问题?
    • @ChristopherDonlan 个人资料!= 始终正确 :-)。你是对的,非确定性不是正确的词。我的意思是该属性在访问时(以及每次访问时)进行评估,而不是按照定义的顺序进行评估。这意味着,例如多次访问Response 会重复发送请求,并且通常很难判断代码的哪一部分何时运行(这就是为什么在惰性语言中进行 I/O 很困难......)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-10-03
    • 2012-10-05
    • 1970-01-01
    • 2020-08-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多