【发布时间】:2021-11-03 15:02:13
【问题描述】:
目标:
使用lexbor 在HTML table 的<td> 标记之间查找和打印一个值。 The details and source code of Lexbor can be found here.
更多详情:
<td> 标签有很多,每个标签都由一个唯一的header 表示。下面是一个简单的示例,其中只有0.7 的第一列值是感兴趣的(即带有header="choose-this-header" 的标签)。
<table>
<tbody>
<tr>
<td header="choose-this-header">0.7</td>
<td header="ignore-this-header">1.3</td>
<td header="ignore-this-header">5.4</td>
</tr>
</tbody>
</table>
因此,找到该值的最佳方法似乎是:
- 在
HTML中搜索header="chosen-header"所在的元素 - 隔离
HTML这一行,提取<td>...</td>标签之间的值
问题:
Based on this lexbor example, step_one.c 成功检测到包含所需header 的HTML 行,但它在终端上打印为<td header="choose-this-header">,没有文本值或关闭</td> 标记。如果有办法将整行(即<td header="choose-this-header">0.7</td>)保存到缓冲区中,则可以使用下面的程序step_two.cbased on this example 来提取0.7 的文本值。
step_one.c
#include "base.h"
#include <lexbor/dom/dom.h>
static void
print_collection_elements(lxb_dom_collection_t *collection)
{
lxb_dom_element_t *element;
for (size_t i = 0; i < lxb_dom_collection_length(collection); i++) {
element = lxb_dom_collection_element(collection, i);
serialize_node(lxb_dom_interface_node(element));
}
lxb_dom_collection_clean(collection);
}
int
main(int argc, const char *argv[])
{
lxb_status_t status;
lxb_dom_element_t *body;
lxb_html_document_t *document;
lxb_dom_collection_t *collection;
const lxb_char_t html[] = "<table>"
"<tbody>"
"<tr>"
"<td header=\"choose-this-header\">0.7</td>"
"<td header=\"ignore-this-header\">1.3</td>"
"<td header=\"ignore-this-header\">5.4</td>"
"</tr>"
"</tbody>"
"</table>";
size_t html_szie = sizeof(html) - 1;
PRINT("HTML:");
PRINT("%s", (const char *) html);
document = parse(html, html_szie);
body = lxb_dom_interface_element(document->body);
collection = lxb_dom_collection_make(&document->dom_document, 128);
if (collection == NULL) {
FAILED("Failed to create Collection object");
}
/* Full match */
status = lxb_dom_elements_by_attr(body, collection,
(const lxb_char_t *) "header", 6,
(const lxb_char_t *) "choose-this-header", 18,
true);
if (status != LXB_STATUS_OK) {
FAILED("Failed to get elements by name");
}
PRINT("\nFull match by 'choose-this-header':");
print_collection_elements(collection);
lxb_dom_collection_destroy(collection, true);
lxb_html_document_destroy(document);
return 0;
}
step_one.c 输出:
HTML:
<table><tbody><tr><td header="choose-this-header">0.7</td><td header="ignore-this-header">1.3</td><td header="ignore-this-header">5.4</td></tr></tbody></table>
Full match by 'choose-this-header':
<td header="choose-this-header"> // no text value or closing tag is printed
step_two.c
#include "lexbor/html/tokenizer.h"
#define FAILED(...) \
do { \
fprintf(stderr, __VA_ARGS__); \
fprintf(stderr, "\n"); \
exit(EXIT_FAILURE); \
} \
while (0)
static lxb_html_token_t *
token_callback(lxb_html_tokenizer_t *tkz, lxb_html_token_t *token, void *ctx)
{
/* Skip all not #text tokens */
if (token->tag_id != LXB_TAG__TEXT) {
return token;
}
printf("%.*s", (int) (token->text_end - token->text_start),
token->text_start);
return token;
}
int
main(int argc, const char *argv[])
{
lxb_status_t status;
lxb_html_tokenizer_t *tkz;
const lxb_char_t data[] = "<td headers=\"choose-this-header\">0.7</td>";
printf("HTML:\n%s\n\n", (char *) data);
printf("Result:\n");
tkz = lxb_html_tokenizer_create();
status = lxb_html_tokenizer_init(tkz);
if (status != LXB_STATUS_OK) {
FAILED("Failed to create tokenizer object");
}
/* Set callback for token */
lxb_html_tokenizer_callback_token_done_set(tkz, token_callback, NULL);
status = lxb_html_tokenizer_begin(tkz);
if (status != LXB_STATUS_OK) {
FAILED("Failed to prepare tokenizer object for parsing");
}
status = lxb_html_tokenizer_chunk(tkz, data, (sizeof(data) - 1));
if (status != LXB_STATUS_OK) {
FAILED("Failed to parse the html data");
}
status = lxb_html_tokenizer_end(tkz);
if (status != LXB_STATUS_OK) {
FAILED("Failed to ending of parsing the html data");
}
printf("\n");
lxb_html_tokenizer_destroy(tkz);
return 0;
}
step_two.c 输出:
HTML:
<td headers="choose-this-header">0.7</td>
Result:
0.7
其他详情:
- 最好继续使用
lexbor,因为它很快 - 使用
Ubuntu 20.04.1 LTS - 用
gcc myprogram.c -llexbor -o myprogram编译 - 各种操作系统的安装说明found here
总结性问题:
Q1. 如何修改程序step_one.c 以将ENTIRE 行保存到缓冲区中?一旦实现这一点,将两个程序组合成一个程序将相对简单,其中step_two.c 中的变量data[] 将是使用step_one.c 中的逻辑找到的整行。
【问题讨论】:
标签: html c web-scraping