【问题标题】:Extract all URLs from HTML in C从 C 中的 HTML 中提取所有 URL
【发布时间】:2020-04-10 15:37:22
【问题描述】:

如何使用 C 标准库提取 HTML 中的所有 URL?

我正在尝试使用 sscanf() 处理它,但是 valgrind 报错(我什至不确定代码在调试成功后是否能满足我的要求,所以如果有其他方法,请告诉我)。我将html内容存储在一个字符串指针中,其中有多个URL(包括绝对URL和相对URL,例如http://www.google.com、//www.google.com、/a.html、a.html等)。我想将它们一个一个提取出来,分别存入另一个字符串指针中。

我也在考虑使用strstr(),但是我不知道如何获取第二个url。

我的代码(我在这里跳过断言)使用 sscanf:

int
main(int argc, char* argv[]) {
    char *remain_html = (char *)malloc(sizeof(char) * 1001);
    char *url = (char *)malloc(sizeof(char) * 101);

    char *html = "<A HREF=\"http://www.google.com\">navigation</a>"
                 "<a href=\"/a.html\">search</a>";
    printf("html: %s\n\n", html);

    sscanf(html, "<a href=\"%s", remain_html);
    printf("after first href tag: %s\n\n", remain_html);
    sscanf(remain_html, "%s\">", url);
    printf("first web: %s\n\n", url);
    sscanf(remain_html, "<a href=\"%s", remain_html);
    printf("after second href tag: %s\n\n", remain_html);

    free(remain_html);
    free(url);
}

valgrind 给出:条件跳转或移动取决于未初始化的值。

如果有人可以帮忙,非常感谢!

【问题讨论】:

  • 您的问题是您帖子的第一句话,还是如何解决底部的错误?
  • 因为错误很清楚,但是要理解它,你必须知道“条件”、“跳转”、“移动”和“单元化”这三个词是什么意思。
  • 为什么要重新发明轮子? Parse html using C 可以追溯到 2009 年。此外,RegEx match open tags except XHTML self-contained tags 的答案包含有关为什么正则表达式和 HTML 不能一起使用的信息。
  • @Robert Harvey 第一句话是我的最终目标。我试图通过以下代码解决它,它给出了错误。我要问的是我的代码是否能给出我的愿望,如何修改它并修复错误,如果没有,解决它的可行方法是什么。

标签: html c regex string


【解决方案1】:

valgrind 警告您有关未初始化的数据(用于测试),考虑到您的程序仅执行 sscanfprintf 这意味着您很可能你的 scanf

有问题

如果我对你的程序稍作改动以打印 sscanf 的结果,那么请显示它得到的许多元素:

int
main(int argc, char* argv[]) {
    char *remain_html = (char *)malloc(sizeof(char) * 1001);
    char *url = (char *)malloc(sizeof(char) * 101);

    char *html = "<A class=\"mw-jump-link\" HREF=\"#mw-head\">Jump to navigation</a>"
                     "<a class=\"mw-jump-link\" href=\"#p-search\">Jump to search</a>";
    printf("html: %s\n\n", html);

    printf("%d\n", sscanf(html, "<a href=\"%s", remain_html));
    printf("after first href tag: %s\n\n", remain_html);
    printf("%d\n", sscanf(remain_html, "%s\">", url));
    printf("first web: %s\n\n", url);
    printf("%d\n", sscanf(remain_html, "<a href=\"%s", remain_html));
    printf("after second href tag: %s\n\n", remain_html);

    free(remain_html);
    free(url);
}

执行是:

pi@raspberrypi:/tmp $ ./a.out
html: <A class="mw-jump-link" HREF="#mw-head">Jump to navigation</a><a class="mw-jump-link" href="#p-search">Jump to search</a>

0
after first href tag: 

-1
first web: 

-1
after second href tag: 

pi@raspberrypi:/tmp $ 

所以第一个 scanf 什么都没有(0 元素),这意味着它没有设置 remain_html 并且当它被下一个 sscanf 具有未定义的行为

因为格式

"<a href=\"%s"

第一个sscanf等待一个以

开头的字符串
 <a href="

html

开头
<A class=

这是不同的,所以它从第二个字符停止并且不设置 remain_html


使用 sscanf 方法不正确,搜索前缀

例子:

#include <stdio.h>
#include <string.h>
#include <ctype.h>

/* in case you do not have that function */
char * strcasestr(char * haystack, char *needle)
{
  while (*haystack) {
    char * ha = haystack;
    char * ne = needle;

    while (tolower(*ha) == tolower(*ne)) {
      if (!*++ne)
        return haystack;
      ha += 1;
    }
    haystack += 1;
  }

  return NULL;
}

int main(int argc, char* argv[]) {
  char *html = "<A HREF=\"http://www.google.com\">navigation</a>"
               "<a href=\"/a.html\">search</a>";
  char * begin = html;
  char * end;

  printf("html: %s\n", html);

  while ((begin = strcasestr(begin, "<a href=\"")) != NULL) {
    begin += 9; /* bypass the header */
    end = strchr(begin, '"');

    if (end != NULL) {
      printf("found '%.*s'\n", (int) (end - begin), begin);
      begin = end + 1;
    }
    else {
      puts("invalid url");
      return -1;
    }
  }
}

编译和执行:

pi@raspberrypi:/tmp $ gcc -Wall a.c
pi@raspberrypi:/tmp $ ./a.out
html: <A HREF="http://www.google.com">navigation</a><a href="/a.html">search</a>
found 'http://www.google.com'
found '/a.html'
pi@raspberrypi:/tmp $ 

注意我知道 strcasestr 的第二个参数是小写的,所以这样做是没用的 tolower(*ne)*ne 已经够了,但是我给出了当前上下文之外的函数定义

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2011-07-09
  • 1970-01-01
  • 1970-01-01
  • 2013-02-28
  • 1970-01-01
  • 2011-01-29
  • 2018-01-08
  • 1970-01-01
相关资源
最近更新 更多