【问题标题】:Programmatically reading a web page以编程方式读取网页
【发布时间】:2010-09-28 04:37:40
【问题描述】:

我想用 C/C++ 编写一个程序,该程序将动态读取网页并从中提取信息。例如,假设您想编写一个应用程序来跟踪和记录 ebay 拍卖。有没有简单的方法来抓取网页?提供此功能的库?是否有一种简单的方法来解析页面以获取特定数据?

【问题讨论】:

  • 在 C/C++ 中非常困难。即使在对正则表达式、XML 解析、HTTP 方法等具有广泛支持的语言(例如 Java)中,它也很烦人。至于 Ebay,它有一个你应该使用的 API。

标签: c++ c http


【解决方案1】:

看看cURL library

 #include <stdio.h>
 #include <curl/curl.h>

 int main(void)
 {
   CURL *curl;
   CURLcode res;

   curl = curl_easy_init();
   if(curl) {
     curl_easy_setopt(curl, CURLOPT_URL, "curl.haxx.se");
     res = curl_easy_perform(curl);
      /* always cleanup */
    curl_easy_cleanup(curl);
   }
   return 0;
 }

顺便说一句,如果不严格要求 C++。我鼓励您尝试 C# 或 Java。它更容易,并且有一个内置的方法。

【讨论】:

  • cURL +1 - 我在我的一个 C++ 应用程序中使用了 cURL,它运行良好,即使使用代理和您可能遇到的所有其他障碍。
  • 如果 curl 为空,最好返回一个错误(在上面的例子中)。
  • 查看 curlpp - cURL 库的 C++ 包装器
  • 点赞推荐 C# 或 Java。 Python 更容易,特别是如果您安装了 Beautiful Soup 包来帮助解析。
  • 为什么这个 +1 被选为答案?实际文件在哪里?代码有什么作用?公然复制和粘贴。
【解决方案2】:

Windows 代码:

#include <winsock2.h>
#include <windows.h>
#include <iostream>
#pragma comment(lib,"ws2_32.lib")
using namespace std;
int main (){
    WSADATA wsaData;
    if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) {
        cout << "WSAStartup failed.\n";
        system("pause");
        return 1;
    }
    SOCKET Socket=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
    struct hostent *host;
    host = gethostbyname("www.google.com");
    SOCKADDR_IN SockAddr;
    SockAddr.sin_port=htons(80);
    SockAddr.sin_family=AF_INET;
    SockAddr.sin_addr.s_addr = *((unsigned long*)host->h_addr);
    cout << "Connecting...\n";
    if(connect(Socket,(SOCKADDR*)(&SockAddr),sizeof(SockAddr)) != 0){
        cout << "Could not connect";
        system("pause");
        return 1;
    }
    cout << "Connected.\n";
    send(Socket,"GET / HTTP/1.1\r\nHost: www.google.com\r\nConnection: close\r\n\r\n", strlen("GET / HTTP/1.1\r\nHost: www.google.com\r\nConnection: close\r\n\r\n"),0);
    char buffer[10000];
    int nDataLength;
    while ((nDataLength = recv(Socket,buffer,10000,0)) > 0){        
        int i = 0;
        while (buffer[i] >= 32 || buffer[i] == '\n' || buffer[i] == '\r') {
            cout << buffer[i];
            i += 1;
        }
    }
    closesocket(Socket);
        WSACleanup();
    system("pause");
    return 0;
}

【讨论】:

  • 在发布多个问题的复制和粘贴样板/逐字答案时要小心,这些往往会被社区标记为“垃圾邮件”。如果您这样做,则通常意味着问题是重复的,因此请将它们标记为:stackoverflow.com/a/12374407/419
  • 这段代码有严重的缺陷: 1) 如果页面超过 10,000 字节且没有不可打印的字符,它将读取超过缓冲区的末尾和 seg-fault。 2) 如果网页中包含 TAB 字符(或其他不可打印字符),则此代码将向前跳过最多 10,000 个字节。 3) 新代码不应使用gethostbyname()。它应该使用getaddrinfo() 并支持 IPv4 和 IPv6。
  • 内部的while循环可以替换成printf("%.*s", nDataLength, buffer);,这样更简单、更快、更安全。
【解决方案3】:

有一个免费的 TCP/IP 库可用于支持 HTTP 和 HTTPS 的 Windows - 使用它非常简单。

Ultimate TCP/IP

CUT_HTTPClient http;
http.GET("http://folder/file.htm", "c:/tmp/process_me.htm");    

您还可以获取文件并将它们存储在内存缓冲区中(通过CUT_DataSource 派生类)。所有常见的 HTTP 支持都在那里 - PUT、HEAD 等。对代理服务器的支持轻而易举,安全套接字也是如此。

【讨论】:

    【解决方案4】:

    您可以通过套接字编程来做到这一点,但是实现可靠地获取页面所需的协议部分是很棘手的。最好使用库,例如​​neon。这很可能安装在大多数 Linux 发行版中。在 FreeBSD 下使用 fetch 库。

    为了解析数据,因为很多页面没有使用有效的 XML,你需要实现启发式,而不是真正的基于 yacc 的解析器。您可以使用正则表达式或状态转换机来实现这些。由于您尝试做的事情涉及大量的反复试验,因此您最好使用脚本语言,例如 Perl。由于网络延迟较高,您不会看到任何性能差异。

    【讨论】:

    • 虽然它们不是有效的 XML,但许多语言都有具有 HTML 解析器的库,这将允许您使用 DOM 接口来解析 HTML 文档。
    • 是的,霓虹灯也不错(但我的大部分经验都是卷曲,如 m3rLinEz 的回答中所述。有什么比较吗?
    【解决方案5】:

    你没有提到任何平台,所以我给你一个Win32的答案。

    从 Internet 下载任何内容的一种简单方法是使用 URLDownloadToFile 并将 IBindStatusCallback 参数设置为 NULL。为了让函数更有用,需要实现回调接口。

    【讨论】:

      【解决方案6】:

      尝试使用 Qt 之类的库,它可以从网络中读取数据并从 xml 文档中获取数据。 This 是如何读取 xml 提要的示例。例如,您可以使用 ebay 提要。

      【讨论】:

        【解决方案7】:

        可以在Multiplatform QT库中完成:

        QByteArray WebpageDownloader::downloadFromUrl(const std::string& url)
        {
            QNetworkAccessManager manager;
            QNetworkReply *response = manager.get(QNetworkRequest(QUrl(url.c_str())));
            QEventLoop event;
            QObject::connect(response, &QNetworkReply::finished, &event, &QEventLoop::quit);
            event.exec();
            return response->readAll();
        }
        

        该数据可以是例如保存到文件,或转换为 std::string:

        const string webpageText = downloadFromUrl(url).toStdString();
        

        记住你需要添加

        QT       += network
        

        到QT项目配置编译代码。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-01-25
          • 1970-01-01
          • 2016-07-26
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多