Clena css-selectors
parent
cb3370c212
commit
0a57d2b2ec
|
@ -3,31 +3,6 @@
|
||||||
// This software is released under the MIT License.
|
// This software is released under the MIT License.
|
||||||
// https://opensource.org/licenses/MIT
|
// https://opensource.org/licenses/MIT
|
||||||
|
|
||||||
export const selectors = {
|
|
||||||
WT_FILTER_POPUP_BUTTON: "a.filterBar-menuTrigger",
|
|
||||||
WT_NEXT_PAGE: "a.pageNav-jump--next",
|
|
||||||
WT_URLS: 'a[href^="/threads/"][data-tp-primary]',
|
|
||||||
WT_UNREAD_THREAD_CHECKBOX: 'input[type="checkbox"][name="unread"]',
|
|
||||||
GS_POSTS: "article.message-body:first-child > div.bbWrapper:first-of-type",
|
|
||||||
GS_RESULT_THREAD_TITLE: "h3.contentRow-title > a",
|
|
||||||
GS_RESULT_BODY: "div.contentRow-main",
|
|
||||||
GS_MEMBERSHIP: "li > a:not(.username)",
|
|
||||||
GET_REQUEST_TOKEN: 'input[name="_xfToken"]',
|
|
||||||
UD_USERNAME_ELEMENT: 'a[href="/account/"] > span.p-navgroup-linkText',
|
|
||||||
UD_AVATAR_PIC: 'a[href="/account/"] > span.avatar > img[class^="avatar"]',
|
|
||||||
LOGIN_MESSAGE_ERROR: "div.blockMessage.blockMessage--error.blockMessage--iconic",
|
|
||||||
LU_TAGS_SCRIPT: "script:contains('latestUpdates')",
|
|
||||||
BK_RESULTS: "ol.listPlain > * div.contentRow-main",
|
|
||||||
BK_POST_URL: "div.contentRow-title > a",
|
|
||||||
BK_DESCRIPTION: "div.contentRow-snippet",
|
|
||||||
BK_POST_OWNER: "div.contentRow-minor > * a.username",
|
|
||||||
BK_TAGS: "div.contentRow-minor > * a.tagItem",
|
|
||||||
/**
|
|
||||||
* Attribute `datetime` contains an ISO date.
|
|
||||||
*/
|
|
||||||
BK_TIME: "div.contentRow-minor > * time"
|
|
||||||
};
|
|
||||||
|
|
||||||
export const GENERIC = {
|
export const GENERIC = {
|
||||||
/**
|
/**
|
||||||
* The ID of the user currently logged into
|
* The ID of the user currently logged into
|
||||||
|
@ -37,7 +12,19 @@ export const GENERIC = {
|
||||||
/**
|
/**
|
||||||
* Banner containing any error messages as text.
|
* Banner containing any error messages as text.
|
||||||
*/
|
*/
|
||||||
ERROR_BANNER: "div.p-body-pageContent > div.blockMessage"
|
ERROR_BANNER: "div.p-body-pageContent > div.blockMessage",
|
||||||
|
/**
|
||||||
|
* Locate the token used for the session.
|
||||||
|
*/
|
||||||
|
GET_REQUEST_TOKEN: 'input[name="_xfToken"]',
|
||||||
|
/**
|
||||||
|
* Block containing the text of any errors that occurred during the login.
|
||||||
|
*/
|
||||||
|
LOGIN_MESSAGE_ERROR: "div.blockMessage.blockMessage--error.blockMessage--iconic",
|
||||||
|
/**
|
||||||
|
* Locate the script containing the tags and prefixes of the platform content in JSON format.
|
||||||
|
*/
|
||||||
|
LATEST_UPDATES_TAGS_SCRIPT: "script:contains('latestUpdates')"
|
||||||
};
|
};
|
||||||
|
|
||||||
export const WATCHED_THREAD = {
|
export const WATCHED_THREAD = {
|
||||||
|
@ -110,6 +97,17 @@ export const THREAD = {
|
||||||
POSTS_IN_PAGE: "article.message"
|
POSTS_IN_PAGE: "article.message"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const THREAD_SEARCH = {
|
||||||
|
/**
|
||||||
|
* Thread title resulting from research.
|
||||||
|
*/
|
||||||
|
THREAD_TITLE: "h3.contentRow-title > a",
|
||||||
|
/**
|
||||||
|
*Thread body resulting from research.
|
||||||
|
*/
|
||||||
|
BODY: "div.contentRow-main"
|
||||||
|
};
|
||||||
|
|
||||||
export const POST = {
|
export const POST = {
|
||||||
/**
|
/**
|
||||||
* Unique post number for the current thread.
|
* Unique post number for the current thread.
|
||||||
|
|
|
@ -14,10 +14,11 @@ import cheerio from "cheerio";
|
||||||
// Modules from file
|
// Modules from file
|
||||||
import shared, { TPrefixDict } from "../shared.js";
|
import shared, { TPrefixDict } from "../shared.js";
|
||||||
import { urls as f95url } from "../constants/url.js";
|
import { urls as f95url } from "../constants/url.js";
|
||||||
import { selectors as f95selector } from "../constants/css-selector.js";
|
import { GENERIC } from "../constants/css-selector.js";
|
||||||
import { fetchHTML } from "../network-helper.js";
|
import { fetchHTML } from "../network-helper.js";
|
||||||
|
|
||||||
//#region Interface definitions
|
//#region Interface definitions
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents the single element contained in the data categories.
|
* Represents the single element contained in the data categories.
|
||||||
*/
|
*/
|
||||||
|
@ -44,9 +45,11 @@ interface ILatestResource {
|
||||||
tags: TPrefixDict;
|
tags: TPrefixDict;
|
||||||
options: string;
|
options: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
//#endregion Interface definitions
|
//#endregion Interface definitions
|
||||||
|
|
||||||
//#region Public methods
|
//#region Public methods
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the basic data used for game data processing
|
* Gets the basic data used for game data processing
|
||||||
* (such as graphics engines and progress statuses)
|
* (such as graphics engines and progress statuses)
|
||||||
|
@ -69,12 +72,13 @@ export default async function fetchPlatformData(): Promise<void> {
|
||||||
} else throw html.value;
|
} else throw html.value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//#endregion Public methods
|
//#endregion Public methods
|
||||||
|
|
||||||
//#region Private methods
|
//#region Private methods
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* Read the platform cache (if available).
|
||||||
* Read the platform cache (if available)
|
|
||||||
*/
|
*/
|
||||||
function readCache(path: string) {
|
function readCache(path: string) {
|
||||||
// Local variables
|
// Local variables
|
||||||
|
@ -95,7 +99,6 @@ function readCache(path: string) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
|
||||||
* Save the current platform variables to disk.
|
* Save the current platform variables to disk.
|
||||||
*/
|
*/
|
||||||
function saveCache(path: string): void {
|
function saveCache(path: string): void {
|
||||||
|
@ -110,7 +113,6 @@ function saveCache(path: string): void {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
|
||||||
* Given the HTML code of the response from the F95Zone,
|
* Given the HTML code of the response from the F95Zone,
|
||||||
* parse it and return the result.
|
* parse it and return the result.
|
||||||
*/
|
*/
|
||||||
|
@ -118,7 +120,7 @@ function parseLatestPlatformHTML(html: string): ILatestResource {
|
||||||
const $ = cheerio.load(html);
|
const $ = cheerio.load(html);
|
||||||
|
|
||||||
// Clean the JSON string
|
// Clean the JSON string
|
||||||
const unparsedText = $(f95selector.LU_TAGS_SCRIPT).html().trim();
|
const unparsedText = $(GENERIC.LATEST_UPDATES_TAGS_SCRIPT).html().trim();
|
||||||
const startIndex = unparsedText.indexOf("{");
|
const startIndex = unparsedText.indexOf("{");
|
||||||
const endIndex = unparsedText.lastIndexOf("}");
|
const endIndex = unparsedText.lastIndexOf("}");
|
||||||
const parsedText = unparsedText.substring(startIndex, endIndex + 1);
|
const parsedText = unparsedText.substring(startIndex, endIndex + 1);
|
||||||
|
@ -126,7 +128,6 @@ function parseLatestPlatformHTML(html: string): ILatestResource {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
|
||||||
* Assign to the local variables the values from the F95Zone.
|
* Assign to the local variables the values from the F95Zone.
|
||||||
*/
|
*/
|
||||||
function assignLatestPlatformData(data: ILatestResource): void {
|
function assignLatestPlatformData(data: ILatestResource): void {
|
||||||
|
@ -154,4 +155,5 @@ function assignLatestPlatformData(data: ILatestResource): void {
|
||||||
shared.setPrefixPair("others", Object.assign({}, scrapedData["Other"]));
|
shared.setPrefixPair("others", Object.assign({}, scrapedData["Other"]));
|
||||||
shared.setPrefixPair("tags", data.tags);
|
shared.setPrefixPair("tags", data.tags);
|
||||||
}
|
}
|
||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
|
@ -10,7 +10,7 @@ import cheerio from "cheerio";
|
||||||
|
|
||||||
// Modules from file
|
// Modules from file
|
||||||
import shared from "../shared.js";
|
import shared from "../shared.js";
|
||||||
import { selectors as f95Selector } from "../constants/css-selector.js";
|
import { THREAD_SEARCH } from "../constants/css-selector.js";
|
||||||
import { urls as f95urls } from "../constants/url.js";
|
import { urls as f95urls } from "../constants/url.js";
|
||||||
import ThreadSearchQuery from "../classes/query/thread-search-query.js";
|
import ThreadSearchQuery from "../classes/query/thread-search-query.js";
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ import ThreadSearchQuery from "../classes/query/thread-search-query.js";
|
||||||
*/
|
*/
|
||||||
export default async function fetchThreadHandiworkURLs(
|
export default async function fetchThreadHandiworkURLs(
|
||||||
query: ThreadSearchQuery,
|
query: ThreadSearchQuery,
|
||||||
limit = 30
|
limit: number = 30
|
||||||
): Promise<string[]> {
|
): Promise<string[]> {
|
||||||
// Execute the query
|
// Execute the query
|
||||||
const response = await query.execute();
|
const response = await query.execute();
|
||||||
|
@ -47,12 +47,12 @@ export default async function fetchThreadHandiworkURLs(
|
||||||
* @param {number} limit
|
* @param {number} limit
|
||||||
* Maximum number of items to get. Default: 30
|
* Maximum number of items to get. Default: 30
|
||||||
*/
|
*/
|
||||||
async function fetchResultURLs(html: string, limit = 30): Promise<string[]> {
|
async function fetchResultURLs(html: string, limit: number = 30): Promise<string[]> {
|
||||||
// Prepare cheerio
|
// Prepare cheerio
|
||||||
const $ = cheerio.load(html);
|
const $ = cheerio.load(html);
|
||||||
|
|
||||||
// Here we get all the DIV that are the body of the various query results
|
// Here we get all the DIV that are the body of the various query results
|
||||||
const results = $("body").find(f95Selector.GS_RESULT_BODY);
|
const results = $("body").find(THREAD_SEARCH.BODY);
|
||||||
|
|
||||||
// Than we extract the URLs
|
// Than we extract the URLs
|
||||||
const urls = results
|
const urls = results
|
||||||
|
@ -74,10 +74,7 @@ async function fetchResultURLs(html: string, limit = 30): Promise<string[]> {
|
||||||
function extractLinkFromResult(selector: cheerio.Cheerio): string {
|
function extractLinkFromResult(selector: cheerio.Cheerio): string {
|
||||||
shared.logger.trace("Extracting thread link from result...");
|
shared.logger.trace("Extracting thread link from result...");
|
||||||
|
|
||||||
const partialLink = selector
|
const partialLink = selector.find(THREAD_SEARCH.THREAD_TITLE).attr("href").trim();
|
||||||
.find(f95Selector.GS_RESULT_THREAD_TITLE)
|
|
||||||
.attr("href")
|
|
||||||
.trim();
|
|
||||||
|
|
||||||
// Compose and return the URL
|
// Compose and return the URL
|
||||||
return new URL(partialLink, f95urls.F95_BASE_URL).toString();
|
return new URL(partialLink, f95urls.F95_BASE_URL).toString();
|
||||||
|
|
|
@ -13,7 +13,7 @@ import axiosCookieJarSupport from "axios-cookiejar-support";
|
||||||
// Modules from file
|
// Modules from file
|
||||||
import shared from "./shared.js";
|
import shared from "./shared.js";
|
||||||
import { urls } from "./constants/url.js";
|
import { urls } from "./constants/url.js";
|
||||||
import { selectors as f95selector } from "./constants/css-selector.js";
|
import { GENERIC } from "./constants/css-selector.js";
|
||||||
import LoginResult from "./classes/login-result.js";
|
import LoginResult from "./classes/login-result.js";
|
||||||
import { failure, Result, success } from "./classes/result.js";
|
import { failure, Result, success } from "./classes/result.js";
|
||||||
import {
|
import {
|
||||||
|
@ -187,7 +187,7 @@ export async function getF95Token(): Promise<string> {
|
||||||
if (response.isSuccess()) {
|
if (response.isSuccess()) {
|
||||||
// The response is a HTML page, we need to find the <input> with name "_xfToken"
|
// The response is a HTML page, we need to find the <input> with name "_xfToken"
|
||||||
const $ = cheerio.load(response.value.data as string);
|
const $ = cheerio.load(response.value.data as string);
|
||||||
return $("body").find(f95selector.GET_REQUEST_TOKEN).attr("value");
|
return $("body").find(GENERIC.GET_REQUEST_TOKEN).attr("value");
|
||||||
} else throw response.value;
|
} else throw response.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -368,7 +368,7 @@ function manageLoginPOSTResponse(response: AxiosResponse<any>) {
|
||||||
|
|
||||||
// Get the error message (if any) and remove the new line chars
|
// Get the error message (if any) and remove the new line chars
|
||||||
const errorMessage = $("body")
|
const errorMessage = $("body")
|
||||||
.find(f95selector.LOGIN_MESSAGE_ERROR)
|
.find(GENERIC.LOGIN_MESSAGE_ERROR)
|
||||||
.text()
|
.text()
|
||||||
.replace(/\n/g, "");
|
.replace(/\n/g, "");
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue