• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

question-closed Pobieranie informacji ze stron internetowych discord bot

0 głosów
2,456 wizyt
pytanie zadane 3 września 2021 w JavaScript przez Maxxxii Obywatel (1,310 p.)
zamknięte 4 września 2021 przez Maxxxii
Cześć ponownie,

tym razem przychodzę z pytaniem w jaki sposób pobrać informacje z różnych stron internetowych.

np. mamy tę stronę: http://metar.vatsim.net/metar.php?id=epgd i chciałbym, żeby wszystko z tej strony (nie jest tam tego dużo) wyświetlało się w wiadomości do użytkownika bota.

Przepraszam, jeżeli jest to błahe pytanie, ale szukałem tego w internecie i nie mogłem znaleźć(chyba, że źle szukałem)

Pozdrawiam
komentarz zamknięcia: znalezienie rozwiązania

1 odpowiedź

0 głosów
odpowiedź 3 września 2021 przez ScriptyChris Mędrzec (190,170 p.)
wybrane 4 września 2021 przez Maxxxii
 
Najlepsza

Możesz użyć dowolnej biblioteki do obsługi zapytań HTTP w Node np. node-fetch lub axios. Pobierz sobie tą stronę (szczegóły znajdziesz w dokumentacjach podlinkowanych bibliotek), i - w zależności, czy potrzebujesz wydobyć ze strony konkretne informacje, czy zadowala Cię całość danych - sparsuj ją do postaci DOM (przy użyciu np. jsdom) i przy użyciu metod DOM-owych pokroju querySelector oraz propertisów typu textContent, odczytaj to czego potrzebujesz.

komentarz 3 września 2021 przez Maxxxii Obywatel (1,310 p.)

Dziękuję za odpowiedź jednak od razu napotkałem problem. Chcąc przetestować czy wszystko działa na etapie node-fetch, wklepałem taki kod:

const fetch = require('node-fetch');

fetch('https://google.com')
    .then(res => res.text())
    .then(text => console.log(text))

lecz niestety otrzymałem błąd

> node bot.js

C:\Users\cichy\Desktop\chartsBot\bot.js:5
const fetch = require("node-fetch")
              ^

Error [ERR_REQUIRE_ESM]: require() of ES Module C:\Users\cichy\Desktop\chartsBot\node_modules\node-fetch\src\index.js from C:\Users\cichy\Desktop\chartsBot\bot.js not supported.
Instead change the require of index.js in C:\Users\cichy\Desktop\chartsBot\bot.js to a dynamic import() which is available in all CommonJS modules. 
    at Object.<anonymous> (C:\Users\cichy\Desktop\chartsBot\bot.js:5:15) {
  code: 'ERR_REQUIRE_ESM'
}
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! chartsbot@1.0.0 start: `node bot.js`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the chartsbot@1.0.0 start script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     C:\Users\cichy\AppData\Roaming\npm-cache\_logs\2021-09-03T14_53_27_209Z-debug.log
The terminal process "C:\WINDOWS\System32\WindowsPowerShell\v1.0\powershell.exe -Command npm run start" terminated with exit code: 1.

i niestety ponownie nic nie mogłem znaleźć w internecie.

Pozdrawiam!

komentarz 3 września 2021 przez ScriptyChris Mędrzec (190,170 p.)

Błąd wskazuje, że moduł node-fetch obsługuje tylko moduły ESM (potwierdza to także dokumentacja). Zaimportuj go więc poprzez składnię import, dynamiczny import (przykład jest w dokumentacji) lub zainstaluj node-fetch w wersji 2.x.

komentarz 3 września 2021 przez Maxxxii Obywatel (1,310 p.)

dobra, po prostu źle przepisałem wzór "import". Niestety mam kolejne pytanie.

Treść ze strony rozumiem jest zapisana w "text" lecz kiedy próbuję ją pokazać na konsoli poza "fetch(url)" wyskakuje, że nie jest zdefiniowana. Jak ją wyprowadzić z metody?

komentarz 3 września 2021 przez ScriptyChris Mędrzec (190,170 p.)

Na screenie niewiele widać. Ale żeby zwrócić wartość, to musisz przypisać ją do zmiennej na zewnątrz lub użyć await na fetch-u.

// (async () => { // jeśli Twój runtime nie wspiera top-level await, to owiń całość w async IIFE

const result = await fetch('some-url.com')
  .then(res => res.text())
  .then(text => {
    console.log('text:', text);
    return text;
  })

console.log('result:', result);

// })(); // zamknięcie opcjonalnego IIFE

 

komentarz 3 września 2021 przez Maxxxii Obywatel (1,310 p.)
teraz jest błąd, że przyjmuje tylko absolute link chociaż wpisuję ten co poprzednio czyli: http://metar.vatsim.net/metar.php?id=epgd i wtedy wszystko działało
komentarz 3 września 2021 przez ScriptyChris Mędrzec (190,170 p.)
Pokaż cały ten błąd i aktualny kod.
komentarz 3 września 2021 przez Maxxxii Obywatel (1,310 p.)
const {Client, Intents, MessageEmbed} = require("discord.js")
const client = new Client({ intents: [Intents.FLAGS.GUILDS, Intents.FLAGS.GUILD_MESSAGES]})
const config = require("./config.json")
const fetch = require("node-fetch")
(async () => {
 
  const result = await fetch('http://metar.vatsim.net/metar.php?id=epgd')
    .then(res => res.text())
    .then(text => {
      console.log('text:', text);
      return text;
    })
   
  console.log('result:', result);
   
});
client.login(config.token)
> Executing task: npm run start <


> chartsbot@1.0.0 start C:\Users\cichy\Desktop\chartsBot
> node bot.js

C:\Users\cichy\Desktop\chartsBot\node_modules\node-fetch\lib\index.js:1305
                throw new TypeError('Only absolute URLs are supported');
                      ^

TypeError: Only absolute URLs are supported
    at getNodeRequestOptions (C:\Users\cichy\Desktop\chartsBot\node_modules\node-fetch\lib\index.js:1305:9)
    at C:\Users\cichy\Desktop\chartsBot\node_modules\node-fetch\lib\index.js:1410:19
    at new Promise (<anonymous>)
    at fetch (C:\Users\cichy\Desktop\chartsBot\node_modules\node-fetch\lib\index.js:1407:9)
    at Object.<anonymous> (C:\Users\cichy\Desktop\chartsBot\bot.js:39:1)
    at Module._compile (node:internal/modules/cjs/loader:1101:14)
    at Object.Module._extensions..js (node:internal/modules/cjs/loader:1153:10)
    at Module.load (node:internal/modules/cjs/loader:981:32)
    at Function.Module._load (node:internal/modules/cjs/loader:822:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:79:12)
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! chartsbot@1.0.0 start: `node bot.js`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the chartsbot@1.0.0 start script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     C:\Users\cichy\AppData\Roaming\npm-cache\_logs\2021-09-03T16_14_04_149Z-debug.log
The terminal process "C:\WINDOWS\System32\WindowsPowerShell\v1.0\powershell.exe -Command npm run start" terminated with exit code: 1.

Terminal will be reused by tasks, press any key to close it.

 

komentarz 3 września 2021 przez ScriptyChris Mędrzec (190,170 p.)

Z której wersji node-fetch ostatecznie korzystasz? Sprawdziłem u siebie na 2.6.1 i pobranie tej strony działa. Wstaw console.log z czymkolwiek do 6 linii - czy ten kod się wykonuje? Bo to IIFE nie wygląda na wywoływane (chyba, że ten kod nie jest 1:1 z Twoim) i w takim przypadku zastanawiałbym się czy jakiś inny fetch nie jest gdzieś używany i on rzuca błędem.

komentarz 3 września 2021 przez Maxxxii Obywatel (1,310 p.)
wersja 2.6.1. wstawiłem console log błąd dalej jest. kod jest 1:1 (skopiowałem go stąd)
komentarz 3 września 2021 przez ScriptyChris Mędrzec (190,170 p.)

Czy ten nowy console.log w 6 linii się wykonał? Jesteś pewien, że używasz fetch tylko w tym miejscu aplikacji? Ile razy próbowałeś instalować node-fetch? Możesz pokazać plik package.json oraz wynik wykonania polecenia npm ls node-fetch w konsoli (będąc w katalogu projektu)? Której wersji Node używasz?

komentarz 3 września 2021 przez Maxxxii Obywatel (1,310 p.)

nie wykonał się, czysty terminal i od razu błąd. fetch jest używany tylko tutaj, tylko kod na górze jest w skrypcie. node-fetch installowałem 2 razy najpierw wersję 3.x odinstalowałem i potem wersję 2.6.1. 

{
  "name": "chartsbot",
  "version": "1.0.0",
  "description": "Bot na discord",
  "main": "bot.js",
  "scripts": {
    "start": "node bot.js"
  },
  "author": "Maxxxii (Kacper Cichocki)",
  "license": "ISC",
  "dependencies": {
    "discord.js": "^13.1.0",
    "node": "16.6.1",
    "node-fetch": "^2.6.1"
  }
}

plik package.json

wynik polecenia w konsoli:

chartsbot@1.0.0 C:\Users\cichy\Desktop\chartsBot
+-- discord.js@13.1.0
| `-- node-fetch@2.6.1
`-- node-fetch@2.6.1

 

komentarz 3 września 2021 przez ScriptyChris Mędrzec (190,170 p.)

nie wykonał się, czysty terminal i od razu błąd

Jeśli wstawiłeś console.log w linie 6 (przed wywołaniem fetch) i on się nie pokazał w konsoli, to cała funkcja nie jest wołana, bo brakuje nawiasów przed średnikiem w linii 16

});

, a powinno być:

})();

Nie zmienia to faktu, że jeśli funkcja faktycznie nie jest wołana, to fetch nie powinien rzucać błędem (bo też nie jest wołany). Czy jeśli zakomentujesz całą funkcję asynchroniczną (linie od 5 do 16), to problem nadal występuje?

Inna sprawa jest taka, że discord.js ma w swoich zależnościach node-fetch też w wersji 2.6.1 (widać to po wyniku polecenia npm ls node-fetch), więc może powstał u Ciebie jakiś konflikt. Wykonaj npm uninstall node-fetch, sprawdź poprzez npm ls node-fetch czy został tylko jeden node-fetch, jako zależność do discord.js, i spróbuj ponowne odpalić apkę. Jeśli to nie pomoże, to usuń folder node_modules i zainstaluj zależności jeszcze raz przez npm install

komentarz 3 września 2021 przez Maxxxii Obywatel (1,310 p.)
gdy dodałem nawiasy w 16 to błąd zmienił się na: TypeError: require(...)(...) is not a function

po zakomentowaniu wszystko się odpala poprawnie
komentarz 3 września 2021 przez ScriptyChris Mędrzec (190,170 p.)

Wstaw w linii 5 (lub na koniec linii 4) średnik - w każdym razie, jeśli masz nowego Node, to nie potrzebujesz tej całej funkcji asynchronicznej, bo masz obsługę top-level await (ja to podałem wtedy w komentarzu na wszelki wypadek). Ale skoro zakomentowany kod nie powoduje błędu, to coś fetch szwankuje. Spróbuj tam podać jakiś prosty URL, typu "https://google.com/" i czy to zadziała?

komentarz 3 września 2021 przez Maxxxii Obywatel (1,310 p.)
Działa! Nawet z tym początkowym linkiem. Tylko teraz jak np. przed tokenem a po funkcji asynchronicznej będę chciał wpisać console.log(result) to już wyskakuje błąd "result is not definied"
komentarz 3 września 2021 przez ScriptyChris Mędrzec (190,170 p.)
edycja 3 września 2021 przez ScriptyChris

Działa! Nawet z tym początkowym linkiem.

A co konkretnie zrobiłeś?

Tylko teraz jak np. przed tokenem a po funkcji asynchronicznej będę chciał wpisać console.log(result) to już wyskakuje błąd "result is not definied"

Nie rozumiem, jak przed tokenem a po funkcji asynchronicznej? Jeśli usunąłeś tą funkcję, to zmienna result jest globalna i dostęp do niej powinien być w całym skrypcie; jeśli nie usunąłeś, to zmienna jest lokalna i widoczna w obrębie tej funkcji (nie poza nią). Jeśli chcesz mieć tą zmienną poza funkcją, to musisz ją zwrócić, ale wtedy znowu potrzebujesz to awaitować, więc albo korzystaj z niej tylko wewnątrz funkcji (to IIFE z async), albo usuń po prostu to IIFE (jak wspomniałem, masz najnowszą wersję Node, więc top-level await będzie działać).


[edycja]

Co do mojego pytania:

A co konkretnie zrobiłeś?

Pewnie brak średnika spowodował, że fetch był wołany z parametrem w postaci referencji do tego IIFE, które swoją drogą nie było wołane przez brak nawiasów na końcu, i dlatego fetch rzucał błąd o nieprawidłowym URL-u, bo funkcja takowym nie jest.

komentarz 3 września 2021 przez Maxxxii Obywatel (1,310 p.)
tak zrobiłem, niestety wyświetla się to: result: Promise { <pending> }
komentarz 3 września 2021 przez ScriptyChris Mędrzec (190,170 p.)
Pokaż aktualny kod.
komentarz 3 września 2021 przez Maxxxii Obywatel (1,310 p.)
const {Client, Intents, MessageEmbed} = require("discord.js")
const client = new Client({ intents: [Intents.FLAGS.GUILDS, Intents.FLAGS.GUILD_MESSAGES]})
const config = require("./config.json")
const fetch = require("node-fetch");

  
const result = fetch('http://metar.vatsim.net/metar.php?id=epgd')
  .then(res => res.text())
  .then(text => {
    console.log('text:', text);
    return text;
  })
    
console.log('result:', result);
    


client.login(config.token)

 

komentarz 3 września 2021 przez ScriptyChris Mędrzec (190,170 p.)

Dodaj słówko await przed wywołaniem fetch.

komentarz 3 września 2021 przez Maxxxii Obywatel (1,310 p.)

 

SyntaxError: await is only valid in async functions and the top level bodies of modules

komentarz 3 września 2021 przez ScriptyChris Mędrzec (190,170 p.)

Ah, żeby top-level await zadziałał, musisz przekształcić skrypt w moduł. Jeśli Ci się nie chce, to możesz korzystać z tego async IIFE, ale wtedy zmienna z fetch będzie dostępna tylko wewnątrz tego IIFE.

komentarz 3 września 2021 przez Maxxxii Obywatel (1,310 p.)
zmieniłem format pliku na .mjs wywaliło błąd, require nie jest dostępny, zmieniłem na import. tylko niestety teraz wywaliło: Cannot read property 'FLAGS' of undefined i zupełnie nie wiem na co to zmienić
komentarz 3 września 2021 przez ScriptyChris Mędrzec (190,170 p.)

Zamień

const {Client, Intents, MessageEmbed} = require("discord.js")

na

import * as Discord from "discord.js";
console.log('Discord:', !!Discord, ' /intents:', Discord.Intents);

i daj znać, co pokaże konsola.

komentarz 3 września 2021 przez Maxxxii Obywatel (1,310 p.)
TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".json" for C:\Users\cichy\Desktop\chartsBot\config.json

czyżby był jakiś format mjson? ;)
komentarz 3 września 2021 przez ScriptyChris Mędrzec (190,170 p.)

Ojej, a skąd nagle odwołanie do jakiegoś pliku konfiguracyjnego?

Dobra... :) Myślę że łatwiej Ci będzie, jeśli po prostu użyjesz async IIFE i require, tak jak miałeś na początku oraz przywróć rozszerzenie z .mjs do .js. Możesz od biedy nawet cały kod owinąć w to IIFE (razem z importami przez require na górze). Tylko pamiętaj, że zmienne utworzone w funkcji nie będą widoczne poza nią, bo ona jest asynchroniczna - mógłbyś niby zadeklarować result z fetch przed IIFE, w IIFE to ustawić i poza IIFE poczekać setTimeout-em lub robić inne hacki, ale to nie ma sensu i będzie z tym więcej problemów niż pożytku.

Zapisz po prostu:

const {Client, Intents, MessageEmbed} = require("discord.js")
const client = new Client({ intents: [Intents.FLAGS.GUILDS, Intents.FLAGS.GUILD_MESSAGES]})
const config = require("./config.json")
const fetch = require("node-fetch")

;(async () => {
  const result = await fetch('http://metar.vatsim.net/metar.php?id=epgd')
    .then(res => res.text())
    .then(text => {
      console.log('text:', text);
      return text;
    })
    
  console.log('result:', result);
   
  client.login(config.token)
})();

 

1
komentarz 3 września 2021 przez Maxxxii Obywatel (1,310 p.)
też myślę, że to będzie lepszy pomysł. Bardzo Ci dziękuję i jestem dozgonnie wdzięczny! Mam u Ciebie dług. :)

Podobne pytania

+1 głos
1 odpowiedź 1,669 wizyt
pytanie zadane 18 września 2021 w JavaScript przez Maxxxii Obywatel (1,310 p.)
0 głosów
0 odpowiedzi 1,187 wizyt
0 głosów
1 odpowiedź 1,180 wizyt
pytanie zadane 23 lipca 2020 w JavaScript przez Samek2222 Początkujący (440 p.)

93,733 zapytań

142,669 odpowiedzi

323,287 komentarzy

63,293 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj

Twierdza Linux. Bezpieczeństwo dla dociekliwych

Aby uzyskać rabat -10%, użyjcie kodu pasja-linux, wpisując go w specjalne pole w koszyku.

...