首页 > 解决方案 > 从 C 中的 HTML 中提取所有 URL

问题描述

如何使用 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 给出:有条件的跳转或移动取决于未初始化的值。

如果有人可以提供帮助,非常感谢!

标签: htmlcregexstring

解决方案


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=

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


使用sscanf不是正确的方法,搜索前缀<a href="可能是大写的,例如使用strcasestr,然后提取 URL 直到结束 "

例子 :

#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就足够了,但是我在当前上下文之外给出了函数的定义


推荐阅读