HTTP-Anfragen (+Arbeit mit Cookies, Proxy, Sessions)
Methoden der Basisklasse
Um Daten von einer Webseite zu sammeln, muss eine HTTP-Anfrage gestellt werden. In der JavaScript API v2 von A-Parser ist eine einfach zu
bedienende Methode zur Ausführung von HTTP-Anfragen implementiert, die als Antwort ein JSON-Objekt in Abhängigkeit von den angegebenen
Methodenargumenten zurückgibt. Im Folgenden erfahren Sie: wie eine HTTP-Anfrage durchgeführt wird, welche Argumente und Optionen die Methode hat, die Ergebnisse
der angegebenen Optionen, wie man die Erfolgsbedingung einer HTTP-Anfrage festlegt und vieles mehr.
Ebenfalls beschrieben sind Methoden, die eine einfache Manipulation von Cookies, Proxys und Sitzungen im erstellten Parser ermöglichen. Nach der erfolgreichen Ausführung einer HTTP-Anfrage, oder vor der Ausführung, können Sie Proxy-/Cookie-/Sitzungsdaten für die Ausführung von HTTP-Anfragen setzen/ändern oder für die Ausführung durch einen anderen Thread mithilfe des Sitzungsmanagers speichern.
Diese Methoden werden von BaseParser geerbt und bilden die Grundlage für die Erstellung eigener Parser.
await this.request(method, url[, queryParams][, opts])
await this.request(method, url, queryParams, opts)
Abrufen einer HTTP-Antwort auf eine Anfrage, wobei als Argumente angegeben werden:
method- Anfragemethode (GET, POST...)url- Link für die AnfragequeryParams- Hash mit GET-Parametern oder Hash mit dem Body der POST-Anfrageopts- Hash mit Anfrageoptionen
opts.check_content
check_content: [ Bedingung1, Bedingung2, ...] - Array von Bedingungen zur Überprüfung des empfangenen Inhalts. Wenn die Überprüfung nicht
erfolgreich ist, wird die Anfrage mit einem anderen Proxy wiederholt.
Möglichkeiten:
- Verwendung von Zeichenfolgen als Bedingungen (Suche nach Vorkommen der Zeichenfolge)
- Verwendung von regulären Ausdrücken als Bedingungen
- Verwendung eigener Prüffunktionen, denen die Daten und Header der Antwort übergeben werden
- Es können mehrere verschiedene Typen von Bedingungen gleichzeitig festgelegt werden
- Für eine logische Negation platzieren Sie die Bedingung in einem Array, d.h.
check_content: ['xxxx', [/yyyy/]]bedeutet, dass die Anfrage als erfolgreich gilt, wenn die empfangenen Daten die Teilzeichenfolgexxxxenthalten und gleichzeitig der reguläre Ausdruck/yyyy/keine Übereinstimmungen auf der Seite findet
Für eine erfolgreiche Anfrage müssen alle im Array angegebenen Prüfungen bestanden werden.
Beispiel (in den Kommentaren ist angegeben, was für eine erfolgreiche Anfrage erforderlich ist):
let response = await this.request('GET', set.query, {}, {
check_content: [
/<\/html>|<\/body>/, // auf der empfangenen Seite muss dieser reguläre Ausdruck zutreffen
['XXXX'], // auf der empfangenen Seite darf diese Teilzeichenfolge nicht vorhanden sein
'</html>', // auf der empfangenen Seite muss diese Teilzeichenfolge vorhanden sein
(data, hdr) => {
return hdr.Status == 200 && data.length > 100;
} // diese Funktion muss true zurückgeben
]
});
opts.decode
decode: 'auto-html' - automatische Erkennung der Kodierung und Konvertierung in utf8
Mögliche Werte:
auto-html- basierend auf Headern, Meta-Tags und dem Seiteninhalt (optimale empfohlene Variante)utf8- gibt an, dass das Dokument in utf8 kodiert ist<encoding>- jede andere Kodierung
opts.headers
headers: { ... } - Hash mit Headern, der Header-Name wird in Kleinschreibung angegeben, es kann u.a. cookie angegeben werden.
Beispiel:
headers: {
accept: 'image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8',
'accept-encoding': 'gzip, deflate, br',
cookie: 'a=321; b=test',
'user-agent' 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.150 Safari/537.36'
}
opts.headers_order
headers_order: ['cookie', 'user-agent', ...] - ermöglicht das Überschreiben der Sortierreihenfolge der Header
opts.onlyheaders
onlyheaders: 0 - bestimmt das Lesen von data; wenn aktiviert (1), werden nur Header empfangen
opts.recurse
recurse: N - maximale Anzahl von Weiterleitungen (Redirects), Standard ist 7, verwenden Sie 0, um Weiterleitungen zu
deaktivieren
opts.proxyretries
proxyretries: N - Anzahl der Versuche zur Ausführung der Anfrage, standardmäßig aus den Parser-Einstellungen übernommen
opts.parsecodes
parsecodes: { ... } - Liste der HTTP-Antwortcodes, die der Parser als erfolgreich betrachtet, standardmäßig aus den
Parser-Einstellungen übernommen. Wenn '*': 1 angegeben wird, gelten alle Antworten als erfolgreich.
Beispiel:
parsecodes: {
200: 1,
403: 1,
500: 1
}
opts.timeout
timeout: N - Antwort-Timeout in Sekunden, standardmäßig aus den Parser-Einstellungen übernommen
opts.do_gzip
do_gzip: 1 - bestimmt, ob Kompression verwendet werden soll (gzip/deflate/br), standardmäßig aktiviert (1), zum Deaktivieren
muss der Wert 0 gesetzt werden
opts.max_size
max_size: N - maximale Größe der Antwort in Bytes, standardmäßig aus den Parser-Einstellungen übernommen
opts.cookie_jar
cookie_jar: { ... } - Hash mit Cookies. Beispiel-Hash:
"cookie_jar": {
"version": 1,
".google.com": {
"/": {
"login": {
"value": "true"
},
"lang": {
"value": "ru-RU"
}
}
},
".test.google.com": {
"/": {
"id": {
"value": 155643
}
}
}
opts.attempt
attempt: N - gibt die Nummer des aktuellen Versuchs an; bei Verwendung dieses Parameters wird der integrierte Versuchs-Handler für
diese Anfrage ignoriert
opts.browser
browser: 1 - automatische Emulation von Browser-Headern (1 - aktiviert, 0 - deaktiviert)
opts.use_proxy
use_proxy: 1 - überschreibt die Proxy-Verwendung für eine einzelne Anfrage innerhalb des JS-Parsers gegenüber dem globalen
Parameter Use proxy (1 - aktiviert, 0 - deaktiviert)
opts.noextraquery
noextraquery: 0 - deaktiviert das Hinzufügen von Extra query string zur Anfrage-URL (1 - aktiviert, 0 - deaktiviert)
opts.save_to_file
save_to_file: file - ermöglicht das Herunterladen einer Datei direkt auf die Festplatte, ohne Speicherung im Arbeitsspeicher. Anstelle von file wird der Name und
Pfad angegeben, unter dem die Datei gespeichert werden soll. Bei Verwendung dieser Option wird alles ignoriert, was mit data zusammenhängt (Inhaltsprüfung
in opts.check_content wird nicht ausgeführt, response.data ist leer usw.)
opts.bypass_cloudflare
bypass_cloudflare: 0 - automatisches Umgehen des JavaScript-Schutzes von CloudFlare unter Verwendung des Chrome-Browsers (1 - aktiviert, 0 -
deaktiviert)
Die Steuerung von Chrome Headless erfolgt in diesem Fall über die Parser-Einstellungen bypassCloudFlareChromeMaxPages
und bypassCloudFlareChromeHeadless, die in static defaultConf und static editableConf angegeben werden müssen:
static defaultConf: typeof BaseParser.defaultConf = {
version: '0.0.1',
results: {
flat: [
['title', 'Title'],
]
},
max_size: 2 * 1024 * 1024,
parsecodes: {
200: 1,
},
results_format: "$title\n",
bypass_cloudflare: 1,
bypassCloudFlareChromeMaxPages: 20,
bypassCloudFlareChromeHeadless: 0
};
static editableConf: typeof BaseParser.editableConf = [
['bypass_cloudflare', ['textfield', 'bypass_cloudflare']],
['bypassCloudFlareChromeMaxPages', ['textfield', 'bypassCloudFlareChromeMaxPages']],
['bypassCloudFlareChromeHeadless', ['textfield', 'bypassCloudFlareChromeHeadless']],
];
async parse(set, results) {
const {success, data, headers} = await this.request('GET', set.query, {}, {
bypass_cloudflare: this.conf.bypass_cloudflare
});
return results;
}
opts.follow_meta_refresh
follow_meta_refresh: 0 - ermöglicht das Folgen von Weiterleitungen, die über ein HTML-Meta-Tag deklariert sind:
<meta http-equiv="refresh" content="time; url=..."/>
opts.redirect_filter
redirect_filter: (hdr) => 1 | 0 - ermöglicht die Definition einer Filterfunktion für Weiterleitungen. Wenn die Funktion
1 zurückgibt, folgt der Parser der Weiterleitung (unter Berücksichtigung des Parameters opts.recurse), bei Rückgabe von 0 wird das Folgen von
Weiterleitungen gestoppt:
redirect_filter: (hdr) => {
if (hdr.location.match(/login/))
return 1;
return 0;
}
opts.follow_common_rediects
opts.follow_common_rediects: 0 - bestimmt, ob Standard-Weiterleitungen gefolgt werden soll (z. B. http -> https
und/oder www.domain.com -> domain.com). Wenn 1 angegeben wird, folgt der Parser Standard-Weiterleitungen ohne Berücksichtigung
des Parameters opts.recurse
opts.http2
opts.http2: 0 - bestimmt, ob das HTTP/2-Protokoll bei der Ausführung von Anfragen verwendet werden soll; standardmäßig
wird HTTP/1.1 verwendet
opts.randomize_tls_fingerprint
opts.randomize_tls_fingerprint: 0 - diese Option ermöglicht das Umgehen von Sperren durch Websites basierend auf dem TLS-Fingerabdruck (1 - aktiviert, 0 -
deaktiviert)
opts.tlsOpts
tlsOpts: { ... } – ermöglicht die
Übergabe von Einstellungen für
HTTPS-Verbindungen
await this.cookies.*
Arbeit mit Cookies für die aktuelle Anfrage
.getAll()
Abrufen eines Arrays von Cookies
await this.cookies.getAll();

.setAll(cookie_jar)
Setzen von Cookies, als Argument muss ein Hash mit Cookies übergeben werden
async parse(set, results) {
this.logger.put("Start scraping query: " + set.query);
await this.cookies.setAll({
"version": 1,
".google.com": {
"/": {
"login": {
"value": "true"
},
"lang": {
"value": "ru-RU"
}
}
},
".test.google.com": {
"/": {
"id": {
"value": 155643
}
}
}
});
let cookies = await this.cookies.getAll();
this.logger.put("Cookies: " + JSON.stringify(cookies));
results.SKIP = 1;
return results;
}

.set(host, path, name, value)
await this.cookies.set(host, path, name, value) - Setzen eines einzelnen Cookies.
Der Sichtbarkeitsbereich eines Cookies hängt direkt vom Format der angegebenen Domain ab, daher wird in host das Vorhandensein eines Punktes vor dem Host berücksichtigt:
- Wenn ein Punkt angegeben ist (
this.cookies.set('.domain.com', ...)), wird der Cookie für alle Subdomains verwendet (z. B. a.domain.com, b.a.domain.com) - Wenn der Host ohne führenden Punkt angegeben ist (
this.cookies.set('site.com', ...)), wird der Cookie strikt für den angegebenen Host verwendet (Host-only Cookie) und nicht an Subdomains übertragen
Dieser Unterschied ist kritisch, da die gleichzeitige Existenz von Cookies mit und ohne Punkt zu Duplikaten und unvorhersehbarem Verhalten der Website führen kann. Überprüfen Sie für eine korrekte Emulation immer, wie genau die Zielseite Cookies setzt (mit Domain-Attribut oder ohne), und verwenden Sie das entsprechende Format.
async parse(set, results) {
this.logger.put("Start scraping query: " + set.query);
await this.cookies.set('.a-parser.com', '/', 'Test-cookie-1', 1);
await this.cookies.set('.a-parser.com', '/', 'Test-cookie-2', 'test-value');
let cookies = await this.cookies.getAll();
this.logger.put("Cookies: " + JSON.stringify(cookies));
results.SKIP = 1;
return results;
}

await this.proxy.*
Arbeit mit Proxys
.next()
Proxy zum nächsten wechseln, der alte Proxy wird für die aktuelle Anfrage nicht mehr verwendet
.ban()
Proxy wechseln und bannen (erforderlich, wenn der Dienst die Arbeit nach IP blockiert), der Proxy wird für die Zeit gebannt,
die in den Parser-Einstellungen angegeben ist (proxybannedcleanup)
.get()
Aktuellen Proxy abrufen (der letzte Proxy, mit dem eine Anfrage gestellt wurde)
.set(proxy, noChange?)
await this.proxy.set('http://127.0.0.1:8080', true) - Proxy für die nächste Anfrage setzen. Der Parameter noChange ist optional; wenn true angegeben wird, wechselt der Proxy nicht zwischen den Versuchen. Standardmäßig ist noChange = false
await this.sessionManager.*
Methoden für die Arbeit mit Sitzungen. Jede Sitzung speichert obligatorisch den verwendeten Proxy und die Cookies. Zudem können optional beliebige Daten gespeichert werden.
Um Sitzungen in einem JS-Parser zu verwenden, muss zuerst zwingend der Sitzungsmanager initialisiert werden. Dies geschieht mit der Methode await this.sessionManagerinit() in init()
.init(opts?)
Initialisierung des Sitzungsmanagers. Als Argument kann ein Objekt (opts) mit zusätzlichen Parametern übergeben werden (alle Parameter sind optional):
name- ermöglicht das Überschreiben des Namens des Parsers, dem die Sitzungen gehören; standardmäßig entspricht er dem Namen des Parsers, in dem die Initialisierung erfolgtwaitForSession- weist den Parser an, auf eine Sitzung zu warten, bis sie erscheint (dies ist nur relevant, wenn mehrere Aufgaben laufen, z. B. eine Sitzungen generiert und die zweite sie verwendet), d.h..get()und.reset()warten immer auf eine Sitzungdomain- gibt an, ob Sitzungen unter allen für diesen Parser gespeicherten gesucht werden sollen (wenn kein Wert gesetzt ist) oder nur für eine bestimmte Domain (Domain muss mit führendem Punkt angegeben werden, z. B..site.com)sessionsKey- ermöglicht das manuelle Festlegen des Namens des Sitzungsspeichers; falls nicht gesetzt, wird der Name automatisch basierend aufname(oder dem Parsernamen, fallsnamenicht gesetzt ist), Domain und Proxychecker generiertexpire- legt die Lebensdauer der Sitzung in Minuten fest, standardmäßig unbegrenzt
Anwendungsbeispiel:
async init() {
await this.sessionManager.init({
name: 'JS::test',
expire: 15 * 60
});
}
.get(opts?)
Abrufen einer neuen Sitzung, muss vor der Durchführung der Anfrage (vor dem ersten Versuch) aufgerufen werden. Gibt ein Objekt mit beliebigen in der Sitzung gespeicherten Daten zurück. Als Argument kann ein Objekt (opts) mit zusätzlichen Parametern übergeben werden (alle Parameter sind optional):
waitTimeout- Möglichkeit anzugeben, wie viele Minuten auf das Erscheinen einer Sitzung gewartet werden soll; arbeitet unabhängig vom ParameterwaitForSessionin.init()(ignoriert diesen), nach Ablauf wird eine leere Sitzung verwendettag- Abrufen einer Sitzung mit einem bestimmten Tag; kann z. B. der Domainname verwendet werden, um Sitzungen an Domains zu binden, von denen sie stammen
Anwendungsbeispiel:
await this.sessionManager.get({
waitTimeout: 10,
tag: 'test session'
})
.reset(opts?)
Löschen der Cookies und Abrufen einer neuen Sitzung. Muss verwendet werden, wenn die Anfrage mit der aktuellen Sitzung nicht erfolgreich war. Gibt ein Objekt mit beliebigen in der Sitzung gespeicherten Daten zurück. Als Argument kann ein Objekt (opts) mit zusätzlichen Parametern übergeben werden (alle Parameter sind optional):
waitTimeout- Möglichkeit anzugeben, wie viele Minuten auf das Erscheinen einer Sitzung gewartet werden soll; arbeitet unabhängig vom ParameterwaitForSessionin.init()(ignoriert diesen), nach Ablauf wird eine leere Sitzung verwendettag- Abrufen einer Sitzung mit einem bestimmten Tag; kann z. B. der Domainname verwendet werden, um Sitzungen an Domains zu binden, von denen sie stammen
Anwendungsbeispiel:
await this.sessionManager.reset({
waitTimeout: 5,
tag: 'test session'
})
.save(sessionOpts?, saveOpts?)
Speichern einer erfolgreichen Sitzung mit der Möglichkeit, beliebige Daten in der Sitzung zu speichern. Unterstützt 2 optionale Argumente:
sessionOpts- beliebige Daten zur Speicherung in der Sitzung; kann eine Zahl, ein String, ein Array oder ein Objekt seinsaveOpts- Objekt mit Parametern zum Speichern der Sitzung:multiply- optionaler Parameter, ermöglicht das Vervielfältigen der Sitzung; als Wert muss eine Zahl angegeben werdentag- optionaler Parameter, legt einen Tag für die gespeicherte Sitzung fest; kann z. B. der Domainname verwendet werden, um Sitzungen an Domains zu binden, von denen sie stammen
Anwendungsbeispiel:
await this.sessionManager.save('some data here', {
multiply: 3,
tag: 'test session'
})
.count()
Gibt die Anzahl der Sitzungen für den aktuellen Sitzungsmanager zurück
Anwendungsbeispiel:
let sesCount = await this.sessionManager.count();
.removeById(sessionId)
Löscht alle Sitzungen mit einer bestimmten ID. Gibt die Anzahl der gelöschten Sitzungen zurück. Die ID der aktuellen Sitzung ist in der Variable this.sessionId enthalten.
Anwendungsbeispiel:
const removedCount = await this.sessionManager.removeById(this.sessionId);
Komplexes Anwendungsbeispiel des Sitzungsmanagers
async init() {
await this.sessionManager.init({
expire: 15 * 60
});
}
async parse(set, results) {
let ses = await this.sessionManager.get();
for(let attempt = 1; attempt <= this.conf.proxyretries; attempt++) {
if(ses)
this.logger.put('Data from session:', ses);
const { success, data } = await this.request('GET', set.query, {}, { attempt });
if(success) {
// process data here
results.success = 1;
break;
} else if(attempt < this.conf.proxyretries) {
const removedCount = await this.sessionManager.removeById(this.sessionId);
this.logger.put(`Removed ${removedCount} bad sessions with id #${this.sessionId}`);
ses = await this.sessionManager.reset();
}
}
if(results.success) {
await this.sessionManager.save('Some data', { multiply: 2 });
this.logger.put(`Total we have ${await this.sessionManager.count()} sessions`);
}
return results;
}

Abfragemethoden await this.request
Methode GET
Anfrageparameter können direkt im Query-String übergeben werden https://a-parser.com/users/?type=staff:
const { success, data, headers } = await this.request('GET', 'https://a-parser.com/users/?type=staff');
Oder als Objekt in queryParams, wobei key: value gleich param=value ist:
const { success, data, headers } = await this.request('GET', 'https://a-parser.com/users/', {
type: 'staff'
});
Methode POST
Wenn die POST-Methode verwendet wird, kann der Body der Anfrage auf zwei Arten übergeben werden:
Auflistung der Variablennamen und ihrer Werte in
queryParams, zum Beispiel:{
"key": set.query,
"id": 1234,
"type": "text"
}Auflistung dieser in
opts.body, zum Beispiel:body: 'key=' + set.query + '&id=1234&type=text'
Wenn der Anfrage-Body als Objekt übergeben wird, wird er automatisch in das Format form-urlencoded umgewandelt; ebenso, wenn body angegeben ist und kein
content-type Header angegeben wurde, wird automatisch content-type: application/x-www-form-urlencoded zugewiesen:
const { success, data, headers } = await this.request('POST', 'https://jsonplaceholder.typicode.com/posts', {
title: 'foo,',
body: 'bar',
userId: 1
});
Wenn der Body der POST-Anfrage ein String oder ein Buffer ist, wird er unverändert übertragen:
// Anfrage mit String
const string = 'title=foo&body=bar&userId=1';
const { success, data, headers } = await this.request('POST', 'https://jsonplaceholder.typicode.com/posts', {}, {
body: string
});
// Anfrage mit Buffer
const string = 'title=foo&body=bar&userId=1';
const buf = Buffer.from(string, 'utf8');
const { success, data, headers } = await this.request('POST', 'https://jsonplaceholder.typicode.com/posts', {}, {
body: buf
});
Dateien hochladen
Senden einer Datei per POST-Anfrage unter Verwendung des Moduls form-data:
const file = fs.readFileSync('pathToFile');
const FormData = require('form-data');
const format = new FormData();
format.append('file', file, 'fileName.ext');
const { success, data, headers } = await this.request('POST', 'https://file.io', {}, {
headers: format.getHeaders(),
body: format.getBuffer()
});
Beispiel für das Senden einer Datei in einer POST-Anfrage mit dem Content-Type multipart/form-data:
const EOL = '\r\n';
const file = fs.readFileSync('pathToFile');
const boundary = '----WebKitFormBoundary' + String(Math.random()).slice(2);
const requestHeaders = {
'content-type': 'multipart/form-data; boundary=' + boundary
};
const body = '--'
+ boundary
+ EOL
+ 'Content-Disposition: form-data; name="file"; filename="fileName.ext"'
+ EOL
+ 'Content-Type: text/html'
+ EOL
+ EOL
+ file
+ EOL
+ '--'
+ boundary
+ '--';
const { success, data, headers } = await this.request('POST', 'https://file.io', {}, {
headers: requestHeaders,
body
});