diff options
author | Aleksi Lindeman <dec05eba@protonmail.com> | 2019-05-25 02:17:15 +0200 |
---|---|---|
committer | Aleksi Lindeman <dec05eba@protonmail.com> | 2019-05-25 02:18:48 +0200 |
commit | 36c6ce46a1abdb08eb9193704b9fce6bc7f3646b (patch) | |
tree | 58e3152073ac2268267e6a4af7963e6528ae4969 |
Initial commit
-rw-r--r-- | .gitignore | 6 | ||||
-rw-r--r-- | LICENSE | 13 | ||||
-rw-r--r-- | README.md | 1 | ||||
-rw-r--r-- | include/quickmedia/HtmlSearch.h | 31 | ||||
-rw-r--r-- | include/quickmedia/NodeSearch.h | 29 | ||||
-rw-r--r-- | include/quickmedia/XpathParser.h | 8 | ||||
-rw-r--r-- | include/quickmedia/XpathTokenizer.h | 32 | ||||
-rw-r--r-- | project.conf | 12 | ||||
-rw-r--r-- | src/HtmlSearch.c | 130 | ||||
-rw-r--r-- | src/NodeSearch.c | 34 | ||||
-rw-r--r-- | src/XpathParser.c | 88 | ||||
-rw-r--r-- | src/XpathTokenizer.c | 104 | ||||
-rw-r--r-- | test_files/test.html | 478 | ||||
-rw-r--r-- | tests/main.c | 33 |
14 files changed, 999 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0dee329 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +# Compiled sibs files +sibs-build/ +compile_commands.json +tests/sibs-build/ +tests/compile_commands.json +.vscode/ @@ -0,0 +1,13 @@ +Copyright 2019 Aleksi Lindeman + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/README.md b/README.md new file mode 100644 index 0000000..a6e5584 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +Html search using xpath, written in C diff --git a/include/quickmedia/HtmlSearch.h b/include/quickmedia/HtmlSearch.h new file mode 100644 index 0000000..e3bea33 --- /dev/null +++ b/include/quickmedia/HtmlSearch.h @@ -0,0 +1,31 @@ +#ifndef QUICKMEDIA_HTML_SEARCH_H +#define QUICKMEDIA_HTML_SEARCH_H + +#include "NodeSearch.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + const void *doc; + const void *node; + void *text; +} QuickMediaHtmlNode; + +/* Returns NULL if attribute doesn't exist or if it doesn't have any value */ +const char* quickmedia_html_node_get_attribute_value(QuickMediaHtmlNode *self, const char *attribute_name); + +/* Returns StringView where data is NULL and size is 0 if node doesn't have any text */ +const QuickMediaStringView quickmedia_html_node_get_text(QuickMediaHtmlNode *self); + +/* @node is only valid within the callback function scope */ +typedef void (*QuickMediaHtmlSearchResultCallback)(QuickMediaHtmlNode *node, void *userdata); + +int quickmedia_html_find_nodes_xpath(const char *html_source, const char *xpath, QuickMediaHtmlSearchResultCallback result_callback, void *userdata); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/quickmedia/NodeSearch.h b/include/quickmedia/NodeSearch.h new file mode 100644 index 0000000..b512296 --- /dev/null +++ b/include/quickmedia/NodeSearch.h @@ -0,0 +1,29 @@ +#ifndef QUICKMEDIA_NODE_SEARCH_H +#define QUICKMEDIA_NODE_SEARCH_H + +typedef struct { + char *name; + char *value; +} QuickMediaNodeSearchParam; + +typedef struct QuickMediaNodeSearch QuickMediaNodeSearch; + +struct QuickMediaNodeSearch { + char *name; /* optional */ + int recursive; + QuickMediaNodeSearchParam param; /* optional */ + int param_defined; + + QuickMediaNodeSearch *child; /* optional */ +}; + +typedef struct { + const char *data; + unsigned long long size; +} QuickMediaStringView; + +void quickmedia_node_search_param_init(QuickMediaNodeSearchParam *self); +void quickmedia_node_search_init(QuickMediaNodeSearch *self); +void quickmedia_node_search_deinit(QuickMediaNodeSearch *self); + +#endif diff --git a/include/quickmedia/XpathParser.h b/include/quickmedia/XpathParser.h new file mode 100644 index 0000000..2dfc81e --- /dev/null +++ b/include/quickmedia/XpathParser.h @@ -0,0 +1,8 @@ +#ifndef QUICKMEDIA_XPATH_PARSER_H +#define QUICKMEDIA_XPATH_PARSER_H + +#include "NodeSearch.h" + +int quickmedia_parse_xpath(const char *xpath, QuickMediaNodeSearch *result); + +#endif diff --git a/include/quickmedia/XpathTokenizer.h b/include/quickmedia/XpathTokenizer.h new file mode 100644 index 0000000..8827cff --- /dev/null +++ b/include/quickmedia/XpathTokenizer.h @@ -0,0 +1,32 @@ +#ifndef QUICKMEDIA_XPATH_TOKENIZER_H +#define QUICKMEDIA_XPATH_TOKENIZER_H + +#include "NodeSearch.h" + +typedef struct { + const char *code; + union { + QuickMediaStringView string; + QuickMediaStringView identifier; + }; +} QuickMediaXpathTokenizer; + +typedef enum { + QUICKMEDIA_XPATH_TOKEN_INVALID, + QUICKMEDIA_XPATH_TOKEN_END_OF_FILE, + QUICKMEDIA_XPATH_TOKEN_CHILD, + QUICKMEDIA_XPATH_TOKEN_CHILD_RECURSIVE, + QUICKMEDIA_XPATH_TOKEN_IDENTIFIER, + QUICKMEDIA_XPATH_TOKEN_STRING, + QUICKMEDIA_XPATH_TOKEN_OPEN_BRACKET, + QUICKMEDIA_XPATH_TOKEN_CLOSING_BRACKET, + QUICKMEDIA_XPATH_TOKEN_EQUAL +} QuickMediaXpathToken; + +void quickmedia_xpath_tokenizer_init(QuickMediaXpathTokenizer *self, const char *xpath); +QuickMediaXpathToken quickmedia_xpath_tokenizer_next(QuickMediaXpathTokenizer *self); +int quickmedia_xpath_tokenizer_next_if(QuickMediaXpathTokenizer *self, QuickMediaXpathToken token); +char* quickmedia_xpath_tokenizer_copy_identifier(QuickMediaXpathTokenizer *self); +char* quickmedia_xpath_tokenizer_copy_string(QuickMediaXpathTokenizer *self); + +#endif diff --git a/project.conf b/project.conf new file mode 100644 index 0000000..6f63e20 --- /dev/null +++ b/project.conf @@ -0,0 +1,12 @@ +[package] +name = "html-search" +type = "static" +version = "0.1.0" +platforms = ["any"] + +[config] +expose_include_dirs = ["include"] +ignore_dirs = ["test_files"] + +[dependencies] +tidy = "5"
\ No newline at end of file diff --git a/src/HtmlSearch.c b/src/HtmlSearch.c new file mode 100644 index 0000000..e59dc1e --- /dev/null +++ b/src/HtmlSearch.c @@ -0,0 +1,130 @@ +#include "../include/quickmedia/HtmlSearch.h" +#include "../include/quickmedia/XpathParser.h" + +#include <tidy.h> +#include <tidybuffio.h> + +static TidyAttr get_attribute_by_name(TidyNode node, const char *name) { + assert(name); + for(TidyAttr attr = tidyAttrFirst(node); attr; attr = tidyAttrNext(attr)) { + const char *attr_name = tidyAttrName(attr); + if(attr_name && strcmp(name, attr_name) == 0) + return attr; + } + return NULL; +} + +static void find_child_nodes(TidyDoc tdoc, TidyNode node, const QuickMediaNodeSearch *search_data, QuickMediaHtmlSearchResultCallback result_callback, void *userdata) { + /* We use two loops because we want to find children before grandchildren */ + for(TidyNode child = tidyGetChild(node); child; child = tidyGetNext(child)) { + const char *child_node_name = tidyNodeGetName(child); + /* A text node doesn't have a name */ + if(!child_node_name) + continue; + + /* Match without node name or node name matches */ + if(!search_data->name || strcmp(search_data->name, child_node_name) == 0) { + #define on_match() do { \ + if(search_data->child) \ + find_child_nodes(tdoc, child, search_data->child, result_callback, userdata); \ + else { \ + QuickMediaHtmlNode node; \ + node.doc = tdoc; \ + node.node = child; \ + node.text = NULL; \ + result_callback(&node, userdata); \ + if(node.text){ \ + tidyBufFree(node.text); \ + free(node.text); \ + } \ + } \ + } while(0) + + /* If we search without param, then it's a match */ + if(!search_data->param_defined) { + on_match(); + continue; + } + + TidyAttr child_attr = get_attribute_by_name(child, search_data->param.name); + /* Couldn't find the param that we want to match against */ + if(!child_attr) + continue; + + const char *attr_value = tidyAttrValue(child_attr); + assert(search_data->param.value); + /* If the param value matches what we want to search for */ + if(attr_value && strcmp(search_data->param.value, attr_value) == 0) { + on_match(); + continue; + } + } + } + + if(search_data->recursive) { + for(TidyNode child = tidyGetChild(node); child; child = tidyGetNext(child)) { + find_child_nodes(tdoc, child, search_data, result_callback, userdata); + } + } +} + +const char* quickmedia_html_node_get_attribute_value(QuickMediaHtmlNode *self, const char *attribute_name) { + TidyAttr attr = get_attribute_by_name((TidyNode)self->node, attribute_name); + if(!attr) + return NULL; + return tidyAttrValue(attr); +} + +const QuickMediaStringView quickmedia_html_node_get_text(QuickMediaHtmlNode *self) { + QuickMediaStringView string_view; + string_view.data = NULL; + string_view.size = 0; + + if(self->text) { + string_view.data = (const char*)((TidyBuffer*)self->text)->bp; + string_view.size = ((TidyBuffer*)self->text)->size; + return string_view; + } + + TidyNode child_node = tidyGetChild(self->node); + if(tidyNodeGetType(child_node) != TidyNode_Text) + return string_view; + + self->text = malloc(sizeof(TidyBuffer)); + tidyBufInit(self->text); + tidyNodeGetText(self->doc, child_node, self->text); + + string_view.data = (const char*)((TidyBuffer*)self->text)->bp; + string_view.size = ((TidyBuffer*)self->text)->size; + return string_view; +} + +static int quickmedia_html_find_nodes(const char *html_source, QuickMediaNodeSearch *search_data, QuickMediaHtmlSearchResultCallback result_callback, void *userdata) { + assert(html_source); + assert(search_data); + assert(result_callback); + if(!html_source || !search_data || !result_callback) + return -1; + + TidyDoc tdoc = tidyCreate(); + tidyOptSetBool(tdoc, TidyShowWarnings, no); + /* tidyOptSetBool(tdoc, TidyForceOutput, yes); */ + int rc = tidyParseString( tdoc, html_source); + if(rc < 0) { + tidyRelease(tdoc); + return rc; + } + + TidyNode root_node = tidyGetRoot(tdoc); + find_child_nodes(tdoc, root_node, search_data, result_callback, userdata); + tidyRelease(tdoc); + return 0; +} + +int quickmedia_html_find_nodes_xpath(const char *html_source, const char *xpath, QuickMediaHtmlSearchResultCallback result_callback, void *userdata) { + QuickMediaNodeSearch search_data; + int xpath_result = quickmedia_parse_xpath(xpath, &search_data); + if(xpath_result != 0) + return xpath_result; + return quickmedia_html_find_nodes(html_source, &search_data, result_callback, userdata); +} diff --git a/src/NodeSearch.c b/src/NodeSearch.c new file mode 100644 index 0000000..198b8cd --- /dev/null +++ b/src/NodeSearch.c @@ -0,0 +1,34 @@ +#include "../include/quickmedia/NodeSearch.h" +#include <stdlib.h> + +void quickmedia_node_search_param_init(QuickMediaNodeSearchParam *self) { + self->name = NULL; + self->value = NULL; +} + +static void quickmedia_node_search_param_deinit(QuickMediaNodeSearchParam *self) { + free(self->name); + free(self->value); + self->name = NULL; + self->value = NULL; +} + +void quickmedia_node_search_init(QuickMediaNodeSearch *self) { + self->name = NULL; + self->recursive = 0; + quickmedia_node_search_param_init(&self->param); + self->param_defined = 0; + self->child = NULL; +} + +void quickmedia_node_search_deinit(QuickMediaNodeSearch *self) { + free(self->name); + self->name = NULL; + quickmedia_node_search_param_deinit(&self->param); + + if(self->child) { + quickmedia_node_search_deinit(self->child); + free(self->child); + self->child = NULL; + } +} diff --git a/src/XpathParser.c b/src/XpathParser.c new file mode 100644 index 0000000..24e1d6e --- /dev/null +++ b/src/XpathParser.c @@ -0,0 +1,88 @@ +#include "../include/quickmedia/XpathParser.h" +#include "../include/quickmedia/XpathTokenizer.h" +#include <stdlib.h> + +typedef struct { + QuickMediaXpathTokenizer tokenizer; +} QuickMediaXpathParser; + +static void quickmedia_xpath_parser_init(QuickMediaXpathParser *self, const char *xpath) { + quickmedia_xpath_tokenizer_init(&self->tokenizer, xpath); +} + +/* ('[' IDENTIFIER '=' '"' STRING '"' ']')? */ +static int xpath_parse_param(QuickMediaXpathParser *self, QuickMediaNodeSearchParam *result) { + if(quickmedia_xpath_tokenizer_next_if(&self->tokenizer, QUICKMEDIA_XPATH_TOKEN_OPEN_BRACKET) != 0) + return 1; + + QuickMediaXpathToken token = quickmedia_xpath_tokenizer_next(&self->tokenizer); + if(token != QUICKMEDIA_XPATH_TOKEN_IDENTIFIER) + return -1; + + result->name = quickmedia_xpath_tokenizer_copy_identifier(&self->tokenizer); + + token = quickmedia_xpath_tokenizer_next(&self->tokenizer); + if(token != QUICKMEDIA_XPATH_TOKEN_EQUAL) + return -2; + + token = quickmedia_xpath_tokenizer_next(&self->tokenizer); + if(token != QUICKMEDIA_XPATH_TOKEN_STRING) + return -3; + + result->value = quickmedia_xpath_tokenizer_copy_string(&self->tokenizer); + + token = quickmedia_xpath_tokenizer_next(&self->tokenizer); + if(token != QUICKMEDIA_XPATH_TOKEN_CLOSING_BRACKET) + return -4; + + return 0; +} + +static int xpath_parse_node(QuickMediaXpathParser *self, QuickMediaNodeSearch *result) { + quickmedia_node_search_init(result); + QuickMediaXpathToken token = quickmedia_xpath_tokenizer_next(&self->tokenizer); + /* // or / */ + if(token == QUICKMEDIA_XPATH_TOKEN_CHILD || token == QUICKMEDIA_XPATH_TOKEN_CHILD_RECURSIVE) { + result->recursive = (token == QUICKMEDIA_XPATH_TOKEN_CHILD_RECURSIVE); + + token = quickmedia_xpath_tokenizer_next(&self->tokenizer); + if(token != QUICKMEDIA_XPATH_TOKEN_IDENTIFIER) + return -1; + + result->name = quickmedia_xpath_tokenizer_copy_identifier(&self->tokenizer); + + int param_result = xpath_parse_param(self, &result->param); + if(param_result < 0) { + quickmedia_node_search_deinit(result); + return param_result; + } else if(param_result == 0) { + result->param_defined = 1; + } + + result->child = malloc(sizeof(QuickMediaNodeSearch)); + int node_result = xpath_parse_node(self, result->child); + if(node_result > 0) { + node_result = 0; + /* Didn't have child, remove child */ + free(result->child); + result->child = NULL; + } else if(node_result < 0) { + quickmedia_node_search_deinit(result); + } + + return node_result; + } else if(token == QUICKMEDIA_XPATH_TOKEN_END_OF_FILE) { + return 1; + } else { + return -2; + } +} + +int quickmedia_parse_xpath(const char *xpath, QuickMediaNodeSearch *result) { + QuickMediaXpathParser parser; + quickmedia_xpath_parser_init(&parser, xpath); + int parse_result = xpath_parse_node(&parser, result); + if(parse_result > 0) + parse_result = -1; + return parse_result; +} diff --git a/src/XpathTokenizer.c b/src/XpathTokenizer.c new file mode 100644 index 0000000..32bede9 --- /dev/null +++ b/src/XpathTokenizer.c @@ -0,0 +1,104 @@ +#include "../include/quickmedia/XpathTokenizer.h" +#include <stdlib.h> +#include <string.h> + +void quickmedia_xpath_tokenizer_init(QuickMediaXpathTokenizer *self, const char *xpath) { + self->code = xpath; + self->identifier.data = NULL; + self->identifier.size = 0; +} + +static int is_alpha(char c) { + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); +} + +static int is_num(char c) { + return c >= '0' && c <= '9'; +} + +static int is_alphanum(char c) { + return is_alpha(c) || is_num(c); +} + +static const char* find_end_of_string(const char *str, char escape_symbol) { + int escape = 0; + while(*str != '\0') { + char c = *str; + if(c == '\\') { + escape = !escape; + } else if(c == escape_symbol) { + if(!escape) + return str; + } else { + escape = 0; + } + ++str; + } + return str; +} + +QuickMediaXpathToken quickmedia_xpath_tokenizer_next(QuickMediaXpathTokenizer *self) { + char c = *self->code; + if(c == '/') { + ++self->code; + c = *self->code; + if(c == '/') { + ++self->code; + return QUICKMEDIA_XPATH_TOKEN_CHILD_RECURSIVE; + } + return QUICKMEDIA_XPATH_TOKEN_CHILD; + } else if(is_alpha(c)) { + self->identifier.data = self->code; + ++self->code; + while(is_alphanum(*self->code) || *self->code == '_' || *self->code == '-') { + ++self->code; + } + self->identifier.size = self->code - self->identifier.data; + return QUICKMEDIA_XPATH_TOKEN_IDENTIFIER; + } else if(c == '[') { + ++self->code; + return QUICKMEDIA_XPATH_TOKEN_OPEN_BRACKET; + } else if(c == ']') { + ++self->code; + return QUICKMEDIA_XPATH_TOKEN_CLOSING_BRACKET; + } else if(c == '=') { + ++self->code; + return QUICKMEDIA_XPATH_TOKEN_EQUAL; + } else if(c == '"' || c == '\'') { + char escape_symbol = c; + ++self->code; + self->string.data = self->code; + self->code = find_end_of_string(self->string.data, escape_symbol); + if(*self->code == '\0') { + /* Reached end of xpath before end of string */ + return QUICKMEDIA_XPATH_TOKEN_INVALID; + } + self->string.size = self->code - self->string.data; + ++self->code; + return QUICKMEDIA_XPATH_TOKEN_STRING; + } else if(c == '\0') { + return QUICKMEDIA_XPATH_TOKEN_END_OF_FILE; + } else { + /* Invalid symbol @c */ + return QUICKMEDIA_XPATH_TOKEN_INVALID; + } +} + +int quickmedia_xpath_tokenizer_next_if(QuickMediaXpathTokenizer *self, QuickMediaXpathToken token) { + const char *restore_point = self->code; + if(quickmedia_xpath_tokenizer_next(self) == token) + return 0; + self->code = restore_point; + return -1; +} + +char* quickmedia_xpath_tokenizer_copy_identifier(QuickMediaXpathTokenizer *self) { + char *result = malloc(self->identifier.size + 1); + result[self->identifier.size] = '\0'; + memcpy(result, self->identifier.data, self->identifier.size); + return result; +} + +char* quickmedia_xpath_tokenizer_copy_string(QuickMediaXpathTokenizer *self) { + return quickmedia_xpath_tokenizer_copy_identifier(self); +} diff --git a/test_files/test.html b/test_files/test.html new file mode 100644 index 0000000..a33081d --- /dev/null +++ b/test_files/test.html @@ -0,0 +1,478 @@ +<!doctype html> +<html lang="en" prefix="og: http://ogp.me/ns# fb: http://ogp.me/ns/fb#"> +<head> +<link rel="alternate" hreflang="en-US" href="https://manganelo.com/search/naruto" /> +<meta name="google-site-verification" content="N3i4EGIjvenSSdLdsmaEtRf6tCyc6yAj6fa7mBRWZeo" /> +<meta name="robots" content="noindex,nofollow" /> +<meta charset="utf-8"> +<title>Naruto Manga - Browse & Search Manga At MangaNelo</title> +<meta name="description" content="Search: naruto Manga - Search for your favorite mangas scans and scanlations online at Manganelo" /> +<meta name="keywords" itemprop="keywords" content="naruto,manga,read manga,manga online,magna scans,manga volume,manga chapter,online manga,read free manga,read free manga online,manga genre" /> +<meta name="viewport" content="width=device-width" /> +<meta name="twitter:card" content="summary_large_image"> +<meta name="twitter:site" content="manganelo"> +<meta name="twitter:title" content="Naruto Manga - Browse & Search Manga At MangaNelo"> +<meta name="twitter:description" content="Search: naruto, manga,read manga,manga online,magna scans,manga volume,manga chapter,online manga,read free manga,read free manga online,manga genre"> +<meta name="twitter:image" content="https://lh3.googleusercontent.com/-iK1y5xV28gs/WCcslYmPKAI/AAAAAAACQGg/o9pv0oioVlY/s0/5826ca23a4ad3.jpg"> +<meta property="og:type" content="website" /> +<meta property="og:title" content="Naruto Manga - Browse & Search Manga At MangaNelo" /> +<meta property="og:url" content="https://manganelo.com/search/naruto" /> +<meta property="og:image" content="https://lh3.googleusercontent.com/-iK1y5xV28gs/WCcslYmPKAI/AAAAAAACQGg/o9pv0oioVlY/s0/5826ca23a4ad3.jpg" /> +<meta property="og:description" content="Search: naruto, manga,read manga,manga online,magna scans,manga volume,manga chapter,online manga,read free manga,read free manga online,manga genre" /> +<meta property="og:site_name" content="https://manganelo.com/" /> +<meta property="fb:app_id" content="1664224760511779" /> +<link rel="shortcut icon" href="https://manganelo.com/favicon.ico" /> +<script type="text/javascript" src="https://manganelo.com/themes/home/js/jquery-1.9.1.min.js?v=1.2.2"></script> +<script type="text/javascript" src="https://manganelo.com/themes/home/js/owl.carousel.js?v=1.2.2"></script> +<script type="text/javascript" src="https://manganelo.com/themes/home/js/back-to-top.js?v=1.2.2"></script> +<script type="text/javascript" src="https://manganelo.com/themes/home/js/ddimgtooltip.js?v=1.2.2"></script> +<script type="text/javascript" src="https://manganelo.com/themes/home/js/fsearch.js?v=1.2.2"></script> +<script type="text/javascript" src="https://manganelo.com/themes/home/js/custom.js?v=1.2.2"></script> +<script type="text/javascript" src="https://manganelo.com/themes/home/js/cookie.js?v=1.2.2"></script> +<script type="text/javascript" src="https://manganelo.com/themes/starrate/js/starwarsjs.js?v=1.2.2"></script> +<script src="https://manganelo.com/themes/home/js/lab.js"></script> +<link rel="stylesheet" href="https://manganelo.com/themes/home/styles/style.css?v=1.2.2"> +<link rel="stylesheet" href="https://manganelo.com/themes/home/styles/owl.carousel.css?v=1.2.2"> +<link rel="stylesheet" href="https://manganelo.com/themes/home/styles/owl.theme.css?v=1.2.2"> +<link rel="stylesheet" href="https://manganelo.com/themes/home/styles/ddimgtooltip.css?v=1.2.2"> +<link rel="stylesheet" href="https://manganelo.com/themes/home/styles/style_search.css?v=1.2.2"> +<link rel="stylesheet" href="https://manganelo.com/themes/starrate/css/style.css?v=1.2.2" /> +<script type="application/javascript"> + baseurljs = 'https://manganelo.com/'; + tooltypejs = 'Computer'; + + _base_url_search = 'https://manganelo.com/search/'; + _base_url_search_author = "https://manganelo.com/search_author/"; +</script> </head> +<body> +<div id="fb-root"></div> +<script> + $appidfb = '1664224760511779'; + (function(d, s, id) { + var js, fjs = d.getElementsByTagName(s)[0]; + if (d.getElementById(id)) return; + js = d.createElement(s); js.id = id; + js.src = "//connect.facebook.net/en_US/all.js#xfbml=1&appId=" + $appidfb; + fjs.parentNode.insertBefore(js, fjs); + }(document, 'script', 'facebook-jssdk')); +</script> <header> +<div class="container container-top"> +<div class="top-logo"> +<a href="https://manganelo.com/" title="Manga Online"><img src="https://manganelo.com/themes/home/icons/logo.png" alt="Manga Online" title="Manga Online"></a> +</div> +<div class="top-header"> +<div class="searching"> +<form name="frmsearch"> +<input id="search_story" autocomplete="off" placeholder="Search manga..." /> +<div style="display: none;"><input /></div> +</form> +</div> +<div class="user-options"> +<div class="login-top"> +<a rel="nofollow" href="https://user.manganelo.com/login?l=manganelo" class="btn-login">Login</a> +<a rel="nofollow" href="https://user.manganelo.com/register?l=manganelo" class="btn-register">Register</a> +</div> +</div> +</div> +<a class="mobile-menu">MENU</a> +<nav class="wrap-menu-primary"> +<ul id="menu-menu-top" class="menu-primary"> +<li class="menu-item"><a href="https://manganelo.com/">HOME</a></li> +<li class="menu-item"><a href="https://manganelo.com/manga_list?type=latest&category=all&state=all&page=1" title="LATEST MANGA">LATEST MANGA</a></li> +<li class="menu-item"><a href="https://manganelo.com/manga_list?type=topview&category=all&state=all&page=1" title="HOT MANGA">HOT MANGA</a></li> +<li class="menu-item"><a href="https://manganelo.com/manga_list?type=newest&category=all&state=all&page=1" title="NEW MANGA">NEW MANGA</a></li> +<li class="menu-item"><a href="https://manganelo.com/manga_list?type=newest&category=all&state=Completed&page=1" title="COMPLETED MANGA">COMPLETED MANGA</a></li> +</ul> +</nav> +</div> +</header> +<div class="container"> +<div class="slide"> +<h3 class="title update-slide">POPULAR MANGA</h3> +<div id="owl-demo" class="owl-carousel"> +<div class="item"> +<img src="https://avt.mkklcdnv3.com/avatar_225/21619-pn918005.jpg" onerror="javascript:this.src='//manganelo.com/themes/home/images/404-avatar.png';" /> +<div class="slide-caption"> +<h3><a rel="nofollow" href="https://manganelo.com/manga/pn918005" title="Solo Leveling">Solo Leveling</a></h3> +<a rel="nofollow" href="https://manganelo.com/chapter/pn918005/chapter_72" title="Chapter 72">Chapter 72</a> +</div> +</div> +<div class="item"> +<img src="https://avt.mkklcdnv3.com/avatar_225/464-tales_of_demons_and_gods.jpg" onerror="javascript:this.src='//manganelo.com/themes/home/images/404-avatar.png';" /> +<div class="slide-caption"> +<h3><a href="https://manganelo.com/manga/tales_of_demons_and_gods" title="Tales of Demons and Gods">Tales of Demons and Gods</a></h3> +<a href="https://manganelo.com/chapter/tales_of_demons_and_gods/chapter_224" title="Chapter 224: Entering the Black Spring">Chapter 224: Entering the Black Spring</a> +</div> +</div> +<div class="item"> +<img src="https://avt.mkklcdnv3.com/avatar_225/19862-apotheosis.jpg" onerror="javascript:this.src='//manganelo.com/themes/home/images/404-avatar.png';" /> +<div class="slide-caption"> +<h3><a href="https://manganelo.com/manga/apotheosis" title="Apotheosis">Apotheosis</a></h3> +<a href="https://manganelo.com/chapter/apotheosis/chapter_164" title="Chapter 164">Chapter 164</a> +</div> +</div> +<div class="item"> +<img src="https://avt.mkklcdnv3.com/avatar_225/2551-the_great_ruler.jpg" onerror="javascript:this.src='//manganelo.com/themes/home/images/404-avatar.png';" /> +<div class="slide-caption"> +<h3><a href="https://manganelo.com/manga/the_great_ruler" title="The Great Ruler">The Great Ruler</a></h3> +<a href="https://manganelo.com/chapter/the_great_ruler/chapter_127" title="Chapter 127">Chapter 127</a> +</div> +</div> +<div class="item"> +<img src="https://avt.mkklcdnv3.com/avatar_225/19973-everlasting_god_of_sword.jpg" onerror="javascript:this.src='//manganelo.com/themes/home/images/404-avatar.png';" /> +<div class="slide-caption"> +<h3><a href="https://manganelo.com/manga/everlasting_god_of_sword" title="Everlasting God of Sword">Everlasting God of Sword</a></h3> +<a href="https://manganelo.com/chapter/everlasting_god_of_sword/chapter_73" title="Chapter 73">Chapter 73</a> +</div> +</div> +<div class="item"> +<img src="https://avt.mkklcdnv3.com/avatar_225/21339-zu917722.jpg" onerror="javascript:this.src='//manganelo.com/themes/home/images/404-avatar.png';" /> +<div class="slide-caption"> +<h3><a href="https://manganelo.com/manga/zu917722" title="A Returner's Magic Should Be Special">A Returner's Magic Should Be Special</a></h3> +<a href="https://manganelo.com/chapter/zu917722/chapter_64" title="Chapter 64">Chapter 64</a> +</div> +</div> +<div class="item"> +<img src="https://avt.mkklcdnv3.com/avatar_225/20891-spirit_sword_sovereign.jpg" onerror="javascript:this.src='//manganelo.com/themes/home/images/404-avatar.png';" /> +<div class="slide-caption"> +<h3><a href="https://manganelo.com/manga/spirit_sword_sovereign" title="Spirit Sword Sovereign">Spirit Sword Sovereign</a></h3> +<a href="https://manganelo.com/chapter/spirit_sword_sovereign/chapter_184" title="Chapter 184">Chapter 184</a> +</div> +</div> +<div class="item"> +<img src="https://avt.mkklcdnv3.com/avatar_225/22141-wp918498.jpg" onerror="javascript:this.src='//manganelo.com/themes/home/images/404-avatar.png';" /> +<div class="slide-caption"> +<h3><a href="https://manganelo.com/manga/wp918498" title="My Wife is a Demon Queen">My Wife is a Demon Queen</a></h3> +<a href="https://manganelo.com/chapter/wp918498/chapter_72" title="Chapter 72">Chapter 72</a> +</div> +</div> +<div class="item"> +<img src="https://avt.mkklcdnv3.com/avatar_225_new/482-xi919082.jpg" onerror="javascript:this.src='//manganelo.com/themes/home/images/404-avatar.png';" /> +<div class="slide-caption"> +<h3><a href="https://manganelo.com/manga/xi919082" title="The Reincarnation Magician Of The Inferior Eyes">The Reincarnation Magician Of The Inferior Eyes</a></h3> +<a href="https://manganelo.com/chapter/xi919082/chapter_7" title="Chapter 7">Chapter 7</a> +</div> +</div> +<div class="item"> +<img src="https://avt.mkklcdnv3.com/avatar_225/20122-kuro_no_shoukanshi.jpg" onerror="javascript:this.src='//manganelo.com/themes/home/images/404-avatar.png';" /> +<div class="slide-caption"> +<h3><a href="https://manganelo.com/manga/kuro_no_shoukanshi" title="Kuro no Shoukanshi">Kuro no Shoukanshi</a></h3> +<a href="https://manganelo.com/chapter/kuro_no_shoukanshi/chapter_27" title="Chapter 27: Declaration of War II">Chapter 27: Declaration of War II</a> +</div> +</div> +<div class="item"> +<img src="https://avt.mkklcdnv3.com/avatar_225/16363-kimetsu_no_yaiba.jpg" onerror="javascript:this.src='//manganelo.com/themes/home/images/404-avatar.png';" /> +<div class="slide-caption"> +<h3><a rel="nofollow" href="https://manganelo.com/manga/kimetsu_no_yaiba" title="Kimetsu no Yaiba">Kimetsu no Yaiba</a></h3> + <a rel="nofollow" href="https://manganelo.com/chapter/kimetsu_no_yaiba/chapter_158" title="Chapter 158: Absurd">Chapter 158: Absurd</a> +</div> +</div> +<div class="item"> +<img src="https://avt.mkklcdnv3.com/avatar_225/1917-komisan_wa_komyushou_desu.jpg" onerror="javascript:this.src='//manganelo.com/themes/home/images/404-avatar.png';" /> +<div class="slide-caption"> +<h3><a href="https://manganelo.com/manga/komisan_wa_komyushou_desu" title="Komi-san wa Komyushou Desu">Komi-san wa Komyushou Desu</a></h3> +<a href="https://manganelo.com/chapter/komisan_wa_komyushou_desu/chapter_198" title="Chapter 198: Out & Law ~The Movie~">Chapter 198: Out & Law ~The Movie~</a> +</div> +</div> +<div class="item"> +<img src="https://avt.mkklcdnv3.com/avatar_225/19255-the_wrong_way_to_use_healing_magic.jpg" onerror="javascript:this.src='//manganelo.com/themes/home/images/404-avatar.png';" /> +<div class="slide-caption"> +<h3><a rel="nofollow" href="https://manganelo.com/manga/the_wrong_way_to_use_healing_magic" title="The Wrong Way to use Healing Magic">The Wrong Way to use Healing Magic</a></h3> +<a rel="nofollow" href="https://manganelo.com/chapter/the_wrong_way_to_use_healing_magic/chapter_20" title="Chapter 20">Chapter 20</a> +</div> +</div> +<div class="item"> +<img src="https://avt.mkklcdnv3.com/avatar_225/19074-assassins_pride.jpg" onerror="javascript:this.src='//manganelo.com/themes/home/images/404-avatar.png';" /> +<div class="slide-caption"> +<h3><a href="https://manganelo.com/manga/assassins_pride" title="Assassin's Pride">Assassin's Pride</a></h3> +<a href="https://manganelo.com/chapter/assassins_pride/chapter_16.5" title="Vol.3 Chapter 16.5: Extras">Vol.3 Chapter 16.5: Extras</a> +</div> +</div> +<div class="item"> +<img src="https://avt.mkklcdnv3.com/avatar_225/22124-hn918480.jpg" onerror="javascript:this.src='//manganelo.com/themes/home/images/404-avatar.png';" /> +<div class="slide-caption"> +<h3><a href="https://manganelo.com/manga/hn918480" title="Release That Witch">Release That Witch</a></h3> +<a href="https://manganelo.com/chapter/hn918480/chapter_37" title="Chapter 37: Wall of Flames">Chapter 37: Wall of Flames</a> +</div> +</div> +<div class="item"> +<img src="https://avt.mkklcdnv3.com/avatar_225/18045-isekai_yakkyoku.jpg" onerror="javascript:this.src='//manganelo.com/themes/home/images/404-avatar.png';" /> +<div class="slide-caption"> +<h3><a href="https://manganelo.com/manga/isekai_yakkyoku" title="Isekai Yakkyoku">Isekai Yakkyoku</a></h3> +<a href="https://manganelo.com/chapter/isekai_yakkyoku/chapter_21" title="Chapter 21: Cutting Edge">Chapter 21: Cutting Edge</a> +</div> +</div> +<div class="item"> +<img src="https://avt.mkklcdnv3.com/avatar_225/708-tamen_de_gushi.jpg" onerror="javascript:this.src='//manganelo.com/themes/home/images/404-avatar.png';" /> +<div class="slide-caption"> +<h3><a href="https://manganelo.com/manga/tamen_de_gushi" title="Tamen De Gushi">Tamen De Gushi</a></h3> +<a href="https://manganelo.com/chapter/tamen_de_gushi/chapter_185.2" title="Chapter 185.2">Chapter 185.2</a> +</div> +</div> +<div class="item"> +<img src="https://avt.mkklcdnv3.com/avatar_225/19650-god_of_martial_arts.jpg" onerror="javascript:this.src='//manganelo.com/themes/home/images/404-avatar.png';" /> +<div class="slide-caption"> +<h3><a href="https://manganelo.com/manga/god_of_martial_arts" title="God of Martial Arts">God of Martial Arts</a></h3> +<a href="https://manganelo.com/chapter/god_of_martial_arts/chapter_83.2" title="Vol.1 Chapter 83.2: Ba Dao(2)">Vol.1 Chapter 83.2: Ba Dao(2)</a> +</div> +</div> +<div class="item"> +<img src="https://avt.mkklcdnv3.com/avatar_225/422-read_one_punch_man_manga_online_free3.jpg" onerror="javascript:this.src='//manganelo.com/themes/home/images/404-avatar.png';" /> +<div class="slide-caption"> +<h3><a rel="nofollow" href="https://manganelo.com/manga/read_one_punch_man_manga_online_free3" title="Onepunch-Man">Onepunch-Man</a></h3> +<a rel="nofollow" href="https://manganelo.com/chapter/read_one_punch_man_manga_online_free3/chapter_107" title="Chapter 107: N/A">Chapter 107: N/A</a> +</div> +</div> +<div class="item"> +<img src="https://avt.mkklcdnv3.com/avatar_225/19316-saikyou_no_shokugyou_wa_yuusha_demo_kenja_demo_naku_kanteishi_kari_rashii_desu_yo.jpg" onerror="javascript:this.src='//manganelo.com/themes/home/images/404-avatar.png';" /> +<div class="slide-caption"> +<h3><a href="https://manganelo.com/manga/saikyou_no_shokugyou_wa_yuusha_demo_kenja_demo_naku_kanteishi_kari_rashii_desu_yo" title="Saikyou no Shokugyou wa Yuusha demo Kenja demo naku Kanteishi (Kari) rashii desu yo?">Saikyou no Shokugyou wa Yuusha demo Kenja demo naku Kanteishi (Kari) rashii desu yo?</a></h3> +<a href="https://manganelo.com/chapter/saikyou_no_shokugyou_wa_yuusha_demo_kenja_demo_naku_kanteishi_kari_rashii_desu_yo/chapter_16" title="Chapter 16">Chapter 16</a> +</div> +</div> +</div> +</div> +<div class="main-wrapper"> +<div class="leftCol"> +<div style="width: 100%;overflow: hidden;text-align: center;float: left;"> +<div style="max-width: 728px;max-height: 90px;overflow: hidden;margin: 0px auto;"> +<iframe src="/ads/adtrue_728x90_desktop.html" scrolling="no" frameborder="0" style="width: 728px;height: 90px;"></iframe> +</div> +</div> +<div class="breadcrumb breadcrumbs"> +<p> +<a href="https://manganelo.com/"> +<span>Manga Online</span> +</a> +<span>»</span> +<span>Search</span> +</p> +</div> +<div class="daily-update"> +<h3 class="title update-title">Keyword: naruto</h3> +<div class="panel_story_list"> +<div class="story_item"> +<a rel="nofollow" href="https://manganelo.com/manga/read_naruto_manga_online_free3"> +<img src="https://avt.mkklcdnv3.com/avatar_225/1203-read_naruto_manga_online_free3.jpg" alt="Naruto" /> +</a> +<div class="story_item_right"> +<h3 class="story_name"> +<a rel="nofollow" href="https://manganelo.com/manga/read_naruto_manga_online_free3">Naruto</a> +<em class="hot"></em> +</h3> +<em class="story_chapter"> +<a rel="nofollow" href="https://manganelo.com/chapter/read_naruto_manga_online_free3/chapter_700.5" title="Naruto chapter 700.5 : Uzumaki Naruto"> +Chapter 700.5 : Uzumaki Naruto </a> +</em> +<em class="story_chapter"> +<a rel="nofollow" href="https://manganelo.com/chapter/read_naruto_manga_online_free3/chapter_700.1" title="Naruto vol.72 chapter 700.1 : Book of Thunder">Vol.72 Chapter 700.1 : Book Of Thunder</a> +</em> +<span>Author(s) : Kishimoto Masashi</span> +<span>Updated : Jan-20-2016 11:54</span> +<span>View : 13,306,950</span> +</div> +</div> +<div class="story_item"> +<a rel="nofollow" href="https://manganelo.com/manga/boruto_naruto_next_generations"> + <img src="https://avt.mkklcdnv3.com/avatar_225/16679-boruto_naruto_next_generations.jpg" alt="Boruto: Naruto Next Generations" /> +</a> +<div class="story_item_right"> +<h3 class="story_name"> +<a rel="nofollow" href="https://manganelo.com/manga/boruto_naruto_next_generations">Boruto: Naruto Next Generations</a> +<em class=""></em> +</h3> +<em class="story_chapter"> +<a rel="nofollow" href="https://manganelo.com/chapter/boruto_naruto_next_generations/chapter_34" title="Boruto: Naruto Next Generations Chapter 34: Training!!"> +Chapter 34: Training!! </a> +</em> +<em class="story_chapter"> +<a rel="nofollow" href="https://manganelo.com/chapter/boruto_naruto_next_generations/chapter_33" title="Boruto: Naruto Next Generations Chapter 33: Breaking The Limit">Chapter 33: Breaking The Limit</a> +</em> +<span>Author(s) : Kodachi Ukyo, Ikemoto Mikio</span> +<span>Updated : Apr-20-2019 06:52</span> +<span>View : 3,453,805</span> +</div> +</div> +<div class="story_item"> +<a rel="nofollow" href="https://manganelo.com/manga/naruto_gaiden_the_seventh_hokage2"> +<img src="https://avt.mkklcdnv3.com/avatar_225/2790-naruto_gaiden_the_seventh_hokage2.jpg" alt="Naruto Gaiden: The Seventh Hokage" /> +</a> +<div class="story_item_right"> +<h3 class="story_name"> +<a rel="nofollow" href="https://manganelo.com/manga/naruto_gaiden_the_seventh_hokage2">Naruto Gaiden: The Seventh Hokage</a> +<em class=""></em> +</h3> +<em class="story_chapter"> +<a rel="nofollow" href="https://manganelo.com/chapter/naruto_gaiden_the_seventh_hokage2/chapter_10.1" title="Naruto Gaiden: The Seventh Hokage ch.10.1 : Projected Into These Eyes (Full Color Version)"> +Ch.10.1 : Projected Into These Eyes (Full Color Version) </a> +</em> +<em class="story_chapter"> +<a rel="nofollow" href="https://manganelo.com/chapter/naruto_gaiden_the_seventh_hokage2/chapter_10" title="Naruto Gaiden: The Seventh Hokage ch.10 : Projected Into These Eyes">Ch.10 : Projected Into These Eyes</a> +</em> +<span>Author(s) : Kishimoto Masashi</span> +<span>Updated : Jan-20-2016 11:44</span> +<span>View : 230,877</span> +</div> +</div> +<div class="story_item"> +<a rel="nofollow" href="https://manganelo.com/manga/kw919198"> +<img src="https://avt.mkklcdnv3.com/avatar_225_new/598-kw919198.jpg" alt="Naruto - Full Color" /> +</a> +<div class="story_item_right"> +<h3 class="story_name"> +<a rel="nofollow" href="https://manganelo.com/manga/kw919198">Naruto - Full Color</a> +<em class="hot"></em> +</h3> +<em class="story_chapter"> +<a rel="nofollow" href="https://manganelo.com/chapter/kw919198/chapter_46" title="Naruto - Full Color Vol.5 Chapter 46: The Password Is..."> +Vol.5 Chapter 46: The Password Is... </a> +</em> +<em class="story_chapter"> +<a rel="nofollow" href="https://manganelo.com/chapter/kw919198/chapter_45" title="Naruto - Full Color Vol.5 Chapter 45: The Second Exam">Vol.5 Chapter 45: The Second Exam</a> +</em> + <span>Author(s) : Masashi Kishimoto</span> +<span>Updated : May-01-2019 16:19</span> +<span>View : 86,639</span> +</div> +</div> +<div class="story_item"> +<a rel="nofollow" href="https://manganelo.com/manga/bt917589"> +<img src="https://avt.mkklcdnv3.com/avatar_225/21209-bt917589.jpg" alt="Naruto: Chibi Sasuke's Sharingan Legend" /> +</a> +<div class="story_item_right"> +<h3 class="story_name"> +<a rel="nofollow" href="https://manganelo.com/manga/bt917589">Naruto: Chibi Sasuke's Sharingan Legend</a> +<em class=""></em> +</h3> +<em class="story_chapter"> +<a rel="nofollow" href="https://manganelo.com/chapter/bt917589/chapter_23.1" title="Naruto: Chibi Sasuke's Sharingan Legend Volume 3 Final Chapter: The Uchiha Clan!!"> +Volume 3 Final Chapter: The Uchiha Clan!! </a> +</em> +<em class="story_chapter"> +<a rel="nofollow" href="https://manganelo.com/chapter/bt917589/chapter_23" title="Naruto: Chibi Sasuke's Sharingan Legend Chapter 23: Karin's Battle!!">Chapter 23: Karin's Battle!!</a> +</em> +<span>Author(s) : Taira Kenji</span> +<span>Updated : Oct-18-2018 14:15</span> +<span>View : 66,363</span> +</div> +</div> +<div class="story_item"> +<a rel="nofollow" href="https://manganelo.com/manga/seikimatsu_darling"> +<img src="https://avt.mkklcdnv3.com/avatar_225/1804-seikimatsu_darling.jpg" alt="Seikimatsu Darling" /> +</a> +<div class="story_item_right"> +<h3 class="story_name"> +<a href="https://manganelo.com/manga/seikimatsu_darling">Seikimatsu Darling</a> +<em class=""></em> +</h3> +<em class="story_chapter"> +<a href="https://manganelo.com/chapter/seikimatsu_darling/chapter_9" title="Seikimatsu Darling vol.2 chapter 9"> +Vol.2 Chapter 9 </a> +</em> +<em class="story_chapter"> +<a href="https://manganelo.com/chapter/seikimatsu_darling/chapter_8" title="Seikimatsu Darling vol.2 chapter 8">Vol.2 Chapter 8</a> +</em> +<span>Author(s) : Naruto Maki</span> +<span>Updated : Jan-20-2016 13:56</span> +<span>View : 50,352</span> +</div> +</div> +<div class="story_item"> +<a rel="nofollow" href="https://manganelo.com/manga/420_renpai_girl"> +<img src="https://avt.mkklcdnv3.com/avatar_225/5691-420_renpai_girl.jpg" alt="420 Renpai Girl" /> +</a> +<div class="story_item_right"> +<h3 class="story_name"> +<a href="https://manganelo.com/manga/420_renpai_girl">420 Renpai Girl</a> +<em class=""></em> +</h3> +<em class="story_chapter"> +<a href="https://manganelo.com/chapter/420_renpai_girl/chapter_1" title="420 Renpai Girl vol.1 ch.1 : Teaser"> +Vol.1 Ch.1 : Teaser </a> +</em> +<span>Author(s) : Kiriyama Naruto</span> +<span>Updated : Jan-21-2016 13:12</span> +<span>View : 17,103</span> +</div> +</div> +</div> +</div> +<div style="clear: both"></div> +<div style="background: #FFF; float: left; margin-top: 10px;padding: 10px; width: calc(100% - 20px);"> +<div class="fb-comments" data-href="http://manganelo.com/story_list" data-width="100%" data-numposts="10" data-colorscheme="light"></div> +</div> </div> +<div class="middleCol"> +<div style="float: left;width: 100%;text-align: center;"> +<div style="max-width: 300px;max-height: 250px;margin: 0px auto;overflow: hidden;"> +<iframe src="/ads/adtrue_300x250_desktop.html" scrolling="no" frameborder="0" style="width: 300px;height: 250px;"></iframe> +</div> +</div> +<div class="xem-nhieu"> +<h3 class="title all-title">Most Popular Manga</h3> +<div class="all"> +<div class="xem-nhieu-item"> +<h3><a rel="nofollow" href="https://manganelo.com/manga/pn918005" title="Solo Leveling">Solo Leveling - Chapter 72</a></h3> +</div> +<div class="xem-nhieu-item"> +<h3><a href="https://manganelo.com/manga/tales_of_demons_and_gods" title="Tales of Demons and Gods">Tales of Demons and Gods - Chapter 224: Entering the Black Spring</a></h3> +</div> +<div class="xem-nhieu-item"> +<h3><a href="https://manganelo.com/manga/the_great_ruler" title="The Great Ruler">The Great Ruler - Chapter 127</a></h3> +</div> +<div class="xem-nhieu-item"> +<h3><a href="https://manganelo.com/manga/nidoume_no_jinsei_wo_isekai_de" title="Nidoume no Jinsei wo Isekai de">Nidoume no Jinsei wo Isekai de - Vol.7 Chapter 32: It Seems Like Another One</a></h3> +</div> +<div class="xem-nhieu-item"> +<h3><a href="https://manganelo.com/manga/zk919364" title="29-sai Dokushin wa Isekai de Jiyuu ni Ikita……katta">29-sai Dokushin wa Isekai de Jiyuu ni Ikita……katta - Chapter 2.1</a></h3> +</div> +<div class="xem-nhieu-item"> +<h3><a href="https://manganelo.com/manga/wp918498" title="My Wife is a Demon Queen">My Wife is a Demon Queen - Chapter 72</a></h3> +</div> +<div class="xem-nhieu-item"> +<h3><a href="https://manganelo.com/manga/potiondanomi_de_ikinobimasu" title="Potion-danomi de Ikinobimasu!">Potion-danomi de Ikinobimasu! - Chapter 24.2</a></h3> +</div> +<div class="xem-nhieu-item"> +<h3><a href="https://manganelo.com/manga/uu918143" title="My Girlfriend is a Villain">My Girlfriend is a Villain - Chapter 26: Childhood Nightmare</a></h3> +</div> +<div class="xem-nhieu-item"> +<h3><a href="https://manganelo.com/manga/god_of_martial_arts" title="God of Martial Arts">God of Martial Arts - Vol.1 Chapter 83.2: Ba Dao(2)</a></h3> +</div> +<div class="xem-nhieu-item"> +<h3><a href="https://manganelo.com/manga/spirit_sword_sovereign" title="Spirit Sword Sovereign">Spirit Sword Sovereign - Chapter 184</a></h3> +</div> +</div> +</div> +<div class="panel-category"> +<h3 class="panel-category-title">GENRES</h3> +<table> +<tbody> +<tr> +<td><a rel="nofollow" href="https://manganelo.com/manga_list?type=latest&category=all&state=all&page=1">Latest</a></td> +<td><a rel="nofollow" href="https://manganelo.com/manga_list?type=newest&category=all&state=all&page=1">Newest</a></td> +<td><a rel="nofollow" href="https://manganelo.com/manga_list?type=topview&category=all&state=all&page=1">Top view</a></td> +</tr> +<tr class="bordertop"> +<td><a rel="nofollow" href="https://manganelo.com/manga_list?type=latest&category=all&state=all&page=1">ALL</a></td> +<td><a rel="nofollow" href="https://manganelo.com/manga_list?type=latest&category=all&state=completed&page=1">Completed</a></td> +<td><a rel="nofollow" href="https://manganelo.com/manga_list?type=latest&category=all&state=ongoing&page=1">Ongoing</a></td> +</tr> +<tr class="bordertop"><td><a rel="nofollow" href="https://manganelo.com/manga_list?type=latest&category=all&state=all&page=1">ALL</a></td><td><a rel="nofollow" href="https://manganelo.com/manga_list?type=latest&category=2&state=all&page=1" title="Action" />Action</a></td><td><a rel="nofollow" href="https://manganelo.com/manga_list?type=latest&category=3&state=all&page=1" title="Adult" />Adult</a></td></tr><tr><td><a rel="nofollow" href="https://manganelo.com/manga_list?type=latest&category=4&state=all&page=1" title="Adventure" />Adventure</a></td><td><a rel="nofollow" href="https://manganelo.com/manga_list?type=latest&category=6&state=all&page=1" title="Comedy" />Comedy</a></td><td><a rel="nofollow" href="https://manganelo.com/manga_list?type=latest&category=7&state=all&page=1" title="Cooking" />Cooking</a></td></tr><tr><td><a rel="nofollow" href="https://manganelo.com/manga_list?type=latest&category=9&state=all&page=1" title="Doujinshi" />Doujinshi</a></td><td><a rel="nofollow" href="https://manganelo.com/manga_list?type=latest&category=10&state=all&page=1" title="Drama" />Drama</a></td><td><a rel="nofollow" href="https://manganelo.com/manga_list?type=latest&category=11&state=all&page=1" title="Ecchi" />Ecchi</a></td></tr><tr><td><a rel="nofollow" href="https://manganelo.com/manga_list?type=latest&category=12&state=all&page=1" title="Fantasy" />Fantasy</a></td><td><a rel="nofollow" href="https://manganelo.com/manga_list?type=latest&category=13&state=all&page=1" title="Gender bender" />Gender bender</a></td><td><a rel="nofollow" href="https://manganelo.com/manga_list?type=latest&category=14&state=all&page=1" title="Harem" />Harem</a></td></tr><tr><td><a rel="nofollow" href="https://manganelo.com/manga_list?type=latest&category=15&state=all&page=1" title="Historical" />Historical</a></td><td><a rel="nofollow" href="https://manganelo.com/manga_list?type=latest&category=16&state=all&page=1" title="Horror" />Horror</a></td><td><a rel="nofollow" href="https://manganelo.com/manga_list?type=latest&category=17&state=all&page=1" title="Josei" />Josei</a></td></tr><tr><td><a rel="nofollow" href="https://manganelo.com/manga_list?type=latest&category=44&state=all&page=1" title="Manhua" />Manhua</a></td><td><a rel="nofollow" href="https://manganelo.com/manga_list?type=latest&category=43&state=all&page=1" title="Manhwa" />Manhwa</a></td><td><a rel="nofollow" href="https://manganelo.com/manga_list?type=latest&category=19&state=all&page=1" title="Martial arts" />Martial arts</a></td></tr><tr><td><a rel="nofollow" href="https://manganelo.com/manga_list?type=latest&category=20&state=all&page=1" title="Mature" />Mature</a></td><td><a rel="nofollow" href="https://manganelo.com/manga_list?type=latest&category=21&state=all&page=1" title="Mecha" />Mecha</a></td><td><a rel="nofollow" href="https://manganelo.com/manga_list?type=latest&category=22&state=all&page=1" title="Medical" />Medical</a></td></tr><tr><td><a rel="nofollow" href="https://manganelo.com/manga_list?type=latest&category=24&state=all&page=1" title="Mystery" />Mystery</a></td><td><a rel="nofollow" href="https://manganelo.com/manga_list?type=latest&category=25&state=all&page=1" title="One shot" />One shot</a></td><td><a rel="nofollow" href="https://manganelo.com/manga_list?type=latest&category=26&state=all&page=1" title="Psychological" />Psychological</a></td></tr><tr><td><a rel="nofollow" href="https://manganelo.com/manga_list?type=latest&category=27&state=all&page=1" title="Romance" />Romance</a></td><td><a rel="nofollow" href="https://manganelo.com/manga_list?type=latest&category=28&state=all&page=1" title="School life" />School life</a></td><td><a rel="nofollow" href="https://manganelo.com/manga_list?type=latest&category=29&state=all&page=1" title="Sci fi" />Sci fi</a></td></tr><tr><td><a rel="nofollow" href="https://manganelo.com/manga_list?type=latest&category=30&state=all&page=1" title="Seinen" />Seinen</a></td><td><a rel="nofollow" href="https://manganelo.com/manga_list?type=latest&category=31&state=all&page=1" title="Shoujo" />Shoujo</a></td><td><a rel="nofollow" href="https://manganelo.com/manga_list?type=latest&category=32&state=all&page=1" title="Shoujo ai" />Shoujo ai</a></td></tr><tr><td><a rel="nofollow" href="https://manganelo.com/manga_list?type=latest&category=33&state=all&page=1" title="Shounen" />Shounen</a></td><td><a rel="nofollow" href="https://manganelo.com/manga_list?type=latest&category=34&state=all&page=1" title="Shounen ai" />Shounen ai</a></td><td><a rel="nofollow" href="https://manganelo.com/manga_list?type=latest&category=35&state=all&page=1" title="Slice of life" />Slice of life</a></td></tr><tr><td><a rel="nofollow" href="https://manganelo.com/manga_list?type=latest&category=36&state=all&page=1" title="Smut" />Smut</a></td><td><a rel="nofollow" href="https://manganelo.com/manga_list?type=latest&category=37&state=all&page=1" title="Sports" />Sports</a></td><td><a rel="nofollow" href="https://manganelo.com/manga_list?type=latest&category=38&state=all&page=1" title="Supernatural" />Supernatural</a></td></tr><tr><td><a rel="nofollow" href="https://manganelo.com/manga_list?type=latest&category=39&state=all&page=1" title="Tragedy" />Tragedy</a></td><td><a rel="nofollow" href="https://manganelo.com/manga_list?type=latest&category=40&state=all&page=1" title="Webtoons" />Webtoons</a></td><td><a rel="nofollow" href="https://manganelo.com/manga_list?type=latest&category=41&state=all&page=1" title="Yaoi" />Yaoi</a></td></tr><tr><td><a rel="nofollow" href="https://manganelo.com/manga_list?type=latest&category=42&state=all&page=1" title="Yuri" />Yuri</a></td></tr> </tbody> +</table> +</div> <div style="float: left;width: 100%;text-align: center;"> +<div style="max-width: 336px;max-height: 280px;margin: 0px auto;overflow: hidden;"> +<iframe src="/ads/bidgear_300x250_desktop.html" scrolling="no" frameborder="0" style="width: 300px;height: 250px;"></iframe> +</div> +</div> +<div style="clear: both"></div> +</div> +</div> +</div> +<footer> +<div class="footer-content"> +<p>©2016 MangaNelo.com, all rights reserved. Top speed, completely free. </p> +<p>Current Time is May-24-2019 08:59:37 AM.</p> +</div> +</footer> +<script type="text/javascript" src="https://manganelo.com/themes/home/js/custom-fotter.js?v=2.9.1"></script> +</body> +</html>
\ No newline at end of file diff --git a/tests/main.c b/tests/main.c new file mode 100644 index 0000000..eb1abc7 --- /dev/null +++ b/tests/main.c @@ -0,0 +1,33 @@ +#include <stdio.h> +#include "../include/quickmedia/HtmlSearch.h" +#include <assert.h> +#include <stdlib.h> + +static char* get_file_content(const char *filepath) { + FILE *file = fopen(filepath, "rb"); + assert(file); + + fseek(file, 0, SEEK_END); + size_t filesize = ftell(file); + fseek(file, 0, SEEK_SET); + + char *buffer = malloc(filesize + 1); + buffer[filesize] = '\0'; + fread(buffer, 1, filesize, file); + + return buffer; +} + +static void result_callback(QuickMediaHtmlNode *node, void *userdata) { + const char *href = quickmedia_html_node_get_attribute_value(node, "href"); + QuickMediaStringView text = quickmedia_html_node_get_text(node); + printf("a href: %s, node value: %.*s\n", href, text.size, text.data); +} + +int main(int argc, char **argv) +{ + char *file_content = get_file_content("test_files/test.html"); + int result = quickmedia_html_find_nodes_xpath(file_content, "//h3[class=\"story_name\"]//a", result_callback, NULL); + free(file_content); + return result; +} |