Fórum Root.cz
Hlavní témata => Vývoj => Téma založeno: GloGlo 29. 06. 2022, 22:57:10
-
Zdravím. Chtěl bych se zeptat, jaký je nejrychlejší a nejednodušší headless browser s Javascriptem. Jde mi o webscrawling.
Momentálně používám headless Chrome přes Selenium, nedělám nic složitýho, ale žere to hrozně moc CPU. (Mám jich spuštěných několik současně).
Potřebuju, aby to umělo Javascript a hlavně fungovalo přes Python, Javu vůbec neumím.
Pokoušel sem se několik hodin rozjet Htmlunit přes selenium-server, ale za živýho boha sem nepřišel na to, jak to udělat.
-
Pyppeteer
-
Pyppeteer
Opravdu je to rychlejší než Selenium + Chrome? O hodně?
-
Pyppeteer
Opravdu je to rychlejší než Selenium + Chrome? O hodně?
v headless modu nejspis ano.
-
Mám jich spuštěných několik současně.
nekolik instanci pythonu nebo nekolik browseru? Ani jedno podle me neni treba, z jednoho skriptu jde otevrit nekolik url najednou v jednom browseru.
-
Pyppeteer
Opravdu je to rychlejší než Selenium + Chrome? O hodně?
v headless modu nejspis ano.
Díval sem se na to, problém je v tom, že to používá asyncio, který neumím :D
Tak sem se ho jakože začal učit, ale je to pro mě dost těžký :D Potřebuju otevřít několik tabů a neustále v nich checkovat zdroják.. Ty taby s požadovanou stránkou sem otevřel, to tak těžký nebylo.. ale aby to permanentně checkovalo zdroják, jak sem pochopil, tak asi nějak musím propojit asyncio + threading a to teda zatím nedávám :D
-
zrovna nedavno tu na asyncio vysly super clanky p tisnovskeho. (na druhou stranu on snad ani neumi napsat spatny clanek na cokoliv :) )
-
jak sem pochopil, tak asi nějak musím propojit asyncio + threading
nepochopil
-
zrovna nedavno tu na asyncio vysly super clanky p tisnovskeho. (na druhou stranu on snad ani neumi napsat spatny clanek na cokoliv :) )
Nevím, jestli sem špatně hledal, ale články byly spíš o threading a o asyncio je jen menší část jednoho z nich - https://www.root.cz/clanky/soubezne-a-paralelne-bezici-ulohy-naprogramovane-v-pythonu-2/#k09
-
jak sem pochopil, tak asi nějak musím propojit asyncio + threading
nepochopil
Můžu se zeptat, jak bys udělal, aby to současně parsovalo třeba pět stránek současně bez použití threading?
Nějak pomocí asyncio.Queue? Jakože jedna stránka bude hotová, pošle signál (nebo jak se tomu říká) další a takhle prostě budou postupovat postupně kolem dokola?
Když sem vytvořil 5 tasks přes asyncio.create_task(), tak to parsovalo jen 1 stránku a ostatní měly smůlu. Jedině když sem udělal parse(data) a následně time.sleep(X), tak to po skončení funkce parse(data) skončilo na další task.
-
jak sem pochopil, tak asi nějak musím propojit asyncio + threading
nepochopil
Můžu se zeptat, jak bys udělal, aby to současně parsovalo třeba pět stránek současně bez použití threading?
Nějak pomocí asyncio.Queue? Jakože jedna stránka bude hotová, pošle signál (nebo jak se tomu říká) další a takhle prostě budou postupovat postupně kolem dokola?
Když sem vytvořil 5 tasks přes asyncio.create_task(), tak to parsovalo jen 1 stránku a ostatní měly smůlu. Jedině když sem udělal parse(data) a následně time.sleep(X), tak to po skončení funkce parse(data) skončilo na další task.
Hele a Google Ti nefunguje? https://stackoverflow.com/questions/28492103/how-to-combine-python-asyncio-with-threads
-
jak sem pochopil, tak asi nějak musím propojit asyncio + threading
nepochopil
Můžu se zeptat, jak bys udělal, aby to současně parsovalo třeba pět stránek současně bez použití threading?
Nějak pomocí asyncio.Queue? Jakože jedna stránka bude hotová, pošle signál (nebo jak se tomu říká) další a takhle prostě budou postupovat postupně kolem dokola?
Když sem vytvořil 5 tasks přes asyncio.create_task(), tak to parsovalo jen 1 stránku a ostatní měly smůlu. Jedině když sem udělal parse(data) a následně time.sleep(X), tak to po skončení funkce parse(data) skončilo na další task.
Hele a Google Ti nefunguje? https://stackoverflow.com/questions/28492103/how-to-combine-python-asyncio-with-threads
on tohle nepotrebuje, to se pouziva, kdyz potrebujes v asyncio aplikaci blokujici volani. pyppeteer je plne neblokujici.
to co chce (vic tabu v jednom browseru) by slo i pomoci selenia a vlaken
-
jak sem pochopil, tak asi nějak musím propojit asyncio + threading
nepochopil
Můžu se zeptat, jak bys udělal, aby to současně parsovalo třeba pět stránek současně bez použití threading?
Nějak pomocí asyncio.Queue? Jakože jedna stránka bude hotová, pošle signál (nebo jak se tomu říká) další a takhle prostě budou postupovat postupně kolem dokola?
Když sem vytvořil 5 tasks přes asyncio.create_task(), tak to parsovalo jen 1 stránku a ostatní měly smůlu. Jedině když sem udělal parse(data) a následně time.sleep(X), tak to po skončení funkce parse(data) skončilo na další task.
priklad
import asyncio
from pyppeteer import launch
async def get_title(browser, url):
page = await browser.newPage()
await page.goto(url)
return await page.title()
async def get_titles(*urls):
browser = await launch()
titles = await asyncio.gather(
*[asyncio.create_task(get_title(browser, url)) for url in urls]
)
await browser.close()
return titles
print(asyncio.run(get_titles("https://example.com", "https://google.com")))
vypise ['Example Domain', 'Google']
-
jak sem pochopil, tak asi nějak musím propojit asyncio + threading
nepochopil
Můžu se zeptat, jak bys udělal, aby to současně parsovalo třeba pět stránek současně bez použití threading?
Nějak pomocí asyncio.Queue? Jakože jedna stránka bude hotová, pošle signál (nebo jak se tomu říká) další a takhle prostě budou postupovat postupně kolem dokola?
Když sem vytvořil 5 tasks přes asyncio.create_task(), tak to parsovalo jen 1 stránku a ostatní měly smůlu. Jedině když sem udělal parse(data) a následně time.sleep(X), tak to po skončení funkce parse(data) skončilo na další task.
Hele a Google Ti nefunguje? https://stackoverflow.com/questions/28492103/how-to-combine-python-asyncio-with-threads
Google mi samozřejmě funguje a taky než sem položil otázku, tak sem zabil docela hodně času pokusem přijít na to sám. Ale tuhle konkrétní věc sem prostě nikde kloudně nenašel no.
Btw až po docela dlouhý době sem se pak někde dočetl, že threading/concurrent.futures/asyncio ty souběhy/konkurenci řeší vlastně všechny a že je blbost ty metody kombinovat, jen to prej přináší problémy.
-
jak sem pochopil, tak asi nějak musím propojit asyncio + threading
nepochopil
Můžu se zeptat, jak bys udělal, aby to současně parsovalo třeba pět stránek současně bez použití threading?
Nějak pomocí asyncio.Queue? Jakože jedna stránka bude hotová, pošle signál (nebo jak se tomu říká) další a takhle prostě budou postupovat postupně kolem dokola?
Když sem vytvořil 5 tasks přes asyncio.create_task(), tak to parsovalo jen 1 stránku a ostatní měly smůlu. Jedině když sem udělal parse(data) a následně time.sleep(X), tak to po skončení funkce parse(data) skončilo na další task.
priklad
import asyncio
from pyppeteer import launch
async def get_title(browser, url):
page = await browser.newPage()
await page.goto(url)
return await page.title()
async def get_titles(*urls):
browser = await launch()
titles = await asyncio.gather(
*[asyncio.create_task(get_title(browser, url)) for url in urls]
)
await browser.close()
return titles
print(asyncio.run(get_titles("https://example.com", "https://google.com")))
vypise ['Example Domain', 'Google']
diky moc!
-
A.P.Hacker:
Předělal sem teda svůj parsovací skript, aby místo selenium používal pyppeteer. Na notebooku mi to funguje dobře.. jenže když ten stejnej kod nahraju na VPS a pokouším se ho spustit, tak se to prostě zasekne u vytvoření stránky
page = await browser.newPage()
... a pak to prostě čeká a nic nedělá.. dokud to nevypnu... Absolutně nechápu proč. Pyppeteer mám samozřejmě nainstalovanej a taky mám stáhlý chrome přes pyppeteer-install.
Celej kod:
import asyncio
from pyppeteer import launch
import datetime
from bs4 import BeautifulSoup
from DB import *
sports = {}
sports['soccer'] = 'https://www.somewebsite.com'
sports['tennis'] = 'https://www.somewebsite.com'
async def AddToDB(data):
# saves any changes to DB
pass
async def parse(data, soup, sport):
# does something
return data
async def CheckPage(browser, sport):
data = {}
url = sports[sport]
page = await browser.newPage()
print (page) # nikdy se nevytiskne
await page.goto(url)
while True:
content = await page.content()
soup = BeautifulSoup(content, 'html.parser')
data = await parse(data, soup, sport)
asyncio.sleep(1)
async def main():
print ("Started: " + datetime.datetime.now().strftime('%H:%M:%S'))
browser = await launch ({ "headless": True, "args": ["--start-maximized"]})
return await asyncio.gather(
*[asyncio.create_task(CheckPage(browser, sport)) for sport in sports]
)
asyncio.run (main())
Nějakej nápad?
-
Btw až po docela dlouhý době sem se pak někde dočetl, že threading/concurrent.futures/asyncio ty souběhy/konkurenci řeší vlastně všechny a že je blbost ty metody kombinovat, jen to prej přináší problémy.
Nevím, jestli rozumím, co máš přesně na mysli. Ale asyncio, by default, přece dělá kooperativní multitasking, to znamená, že pokud v daném tasku něco počítáš a ve frontě už máš další práci, musí další task čekat, to znamená, že se připravuješ o výkon. asyncio, threading a multiprocessing prostě dělají každý něco jiného a nejsou takhle jednoduše zastupitelné. Mrkni třeba sem:
https://realpython.com/python-concurrency/
-
hm k tomu výše.. vypadá to na bug v Pyppeteeru :///
https://github.com/pyppeteer/pyppeteer/issues/395
Tímto se pro mě bohužel pyppeteer stává nepoužitelným
-
Tak tu máme v tom evidentne poriadny hokej.
Táto slučka vyzerá na prvý pohľad ako problém:
while True:
content = await page.content()
soup = BeautifulSoup(content, 'html.parser')
data = await parse(data, soup, sport)
asyncio.sleep(1)
Vytvárať vlastné slučky pomocou while True je big, big no.
Asynchrónne programovanie je založené na slučke udalostí, ktorú však vytvorí
asyncio modul.
asyncio.run function runs the passed coroutine, taking care of managing the
asyncio event loop and finalizing asynchronous generators.
Takmer určite tvoj problém nespôsobil Puppeteer, ale chyba v tvojom programe.
Mne prijde, že sa snažíš vytvoriť pravdepodobne nejaký monitorovací skript.
Ak je to tak, tak si najpr treba vytvoriť skript, ktorý vykoná požadovaný task
a až potom neskôr riešiť monitoring.
Add puppeteer. Headless browser použiješ vtedy, ak sa potrebuješ dostať
za JS bránu, napr. za prihlasovacie okno. Pre ostatné prípady sa bežne
používajú http clienty. Python má httpx, ktorý zvládne aj async programy.
#!/usr/bin/python
import httpx
import asyncio
from bs4 import BeautifulSoup
async def get_async(url):
async with httpx.AsyncClient() as client:
return await client.get(url)
urls = ['http://webcode.me', 'https://httpbin.org',
'https://something.com', 'https://stackoverflow.com',
'https://github.com']
async def launch():
resps = await asyncio.gather(*map(get_async, urls))
data = [resp.text for resp in resps]
for content in data:
soup = BeautifulSoup(content, 'lxml')
print(soup.title)
asyncio.run(launch())
Príklad asynchrónne stiahne HTML kód z viacerých stránok, a výpíše ich
titulky.
Čo je ale vlastne tvoja požiadavka, o čo sa snažíš? Pojem webscrawling
neexistuje, máme web scraping a web crawling. Web scraping je sťahovanie dát
z internetu, trebárs ceny leteniek k danému dňu. Web crawling je to, čo robí
Google.
-
Ten kod se zasekne tak jako tak, na te nekonecne smycce.
volani asyncio.sleep bez await na nic neceka.
tezko rict proc to ze serveru nejde, muze souviset s blacklistovanymi serverovymi IP adresami.
Pokud jsi je zahltil requesty generovanymi tou nekonecnou smyckou bez cekani, je dobra sance, ze te zablokovali.
Ten tazatel na GH to spousti z nejake CI sluzby, tam je take dost velka sance blokace.
-
Add puppeteer. Headless browser použiješ vtedy, ak sa potrebuješ dostať
za JS bránu, napr. za prihlasovacie okno. Pre ostatné prípady sa bežne
používajú http clienty. Python má httpx, ktorý zvládne aj async programy.
casto je samotny obsah generovany javascriptem, ruzne tabulky tahane ajaxem a podobne.
-
Ten kod se zasekne tak jako tak, na te nekonecne smycce.
volani asyncio.sleep bez await na nic neceka.
tezko rict proc to ze serveru nejde, muze souviset s blacklistovanymi serverovymi IP adresami.
Pokud jsi je zahltil requesty generovanymi tou nekonecnou smyckou bez cekani, je dobra sance, ze te zablokovali.
Ten tazatel na GH to spousti z nejake CI sluzby, tam je take dost velka sance blokace.
Ne, chyba nebyla v tom, že by nebyl dostupný nějaký určitý web, ale nešlo mi vůbec v pyppeteeru otevřít nový tab. Zaseklo se to už na await browser.newPage(). Nicméně nakonec sem vyřešil pomocí minimal args:
minimal_args = [
'--autoplay-policy=user-gesture-required',
'--disable-background-networking',
'--disable-background-timer-throttling',
'--disable-backgrounding-occluded-windows',
'--disable-breakpad',
'--disable-client-side-phishing-detection',
'--disable-component-update',
'--disable-default-apps',
'--disable-dev-shm-usage',
'--disable-domain-reliability',
'--disable-features=AudioServiceOutOfProcess',
'--disable-hang-monitor',
'--disable-ipc-flooding-protection',
'--disable-notifications',
'--disable-offer-store-unmasked-wallet-cards',
'--disable-popup-blocking',
'--disable-print-preview',
'--disable-prompt-on-repost',
'--disable-renderer-backgrounding',
'--disable-setuid-sandbox',
'--disable-speech-api',
'--disable-sync',
'--hide-scrollbars',
'--ignore-gpu-blacklist',
'--metrics-recording-only',
'--mute-audio',
'--no-default-browser-check',
'--no-first-run',
'--no-pings',
'--no-sandbox',
'--no-zygote',
'--password-store=basic',
'--use-gl=swiftshader',
'--use-mock-keychain',
'--allow-insecure-localhost',
];
teď mi to na serveru funguje.
Ale teda musím říct, že moje představy, že to takhle bude rychlejší, se absolutně, absolutně vůbec nenaplnily.
Doteď sem používal selenium, jeden tab a prostě rychle za sebou otevíral, checkoval, zavíral stránky.. Ale otevřenej byl vždycky jen jeden tab. Program top mi ukazoval více spuštěnejch procesů chrome, jak kdy, zhruba 5-7 jich bylo, a load average kolísal kolem 3-6.
Jenže teďka, když teda používám ten pyppeteer, jeden spuštěnej browser a 7 otevřenejch tabů, jejichž zdroják checkuju... Spuštěnejch procesů chrome je nějak o dost víc, asi 15-20, a load average je zhruba 3x vyšší.. resp. kolísá cca mezi 10-20.. ale chvilku byl i 50, lol..
-
Tak tu máme v tom evidentne poriadny hokej.
Táto slučka vyzerá na prvý pohľad ako problém:
while True:
content = await page.content()
soup = BeautifulSoup(content, 'html.parser')
data = await parse(data, soup, sport)
asyncio.sleep(1)
Vytvárať vlastné slučky pomocou while True je big, big no.
Asynchrónne programovanie je založené na slučke udalostí, ktorú však vytvorí
asyncio modul.
asyncio.run function runs the passed coroutine, taking care of managing the
asyncio event loop and finalizing asynchronous generators.
Takmer určite tvoj problém nespôsobil Puppeteer, ale chyba v tvojom programe.
Mne prijde, že sa snažíš vytvoriť pravdepodobne nejaký monitorovací skript.
Ak je to tak, tak si najpr treba vytvoriť skript, ktorý vykoná požadovaný task
a až potom neskôr riešiť monitoring.
Add puppeteer. Headless browser použiješ vtedy, ak sa potrebuješ dostať
za JS bránu, napr. za prihlasovacie okno. Pre ostatné prípady sa bežne
používajú http clienty. Python má httpx, ktorý zvládne aj async programy.
#!/usr/bin/python
import httpx
import asyncio
from bs4 import BeautifulSoup
async def get_async(url):
async with httpx.AsyncClient() as client:
return await client.get(url)
urls = ['http://webcode.me', 'https://httpbin.org',
'https://something.com', 'https://stackoverflow.com',
'https://github.com']
async def launch():
resps = await asyncio.gather(*map(get_async, urls))
data = [resp.text for resp in resps]
for content in data:
soup = BeautifulSoup(content, 'lxml')
print(soup.title)
asyncio.run(launch())
Príklad asynchrónne stiahne HTML kód z viacerých stránok, a výpíše ich
titulky.
Čo je ale vlastne tvoja požiadavka, o čo sa snažíš? Pojem webscrawling
neexistuje, máme web scraping a web crawling. Web scraping je sťahovanie dát
z internetu, trebárs ceny leteniek k danému dňu. Web crawling je to, čo robí
Google.
OK. Web scraping. Web s datama, který se v prohlížeči aktualizujou skoro každou sekundu nějak pomocí Ajaxu/JS. Kdybych stáhnul stránku pomocí wget/curl, tak je to nepoužitelná statická stránka bez těch dat. Takže potřebuju mít spuštěnej prohlížeč, který předává zdroják parsovacímu skriptu, který ho projede, podívá se na změny od posledního checku a pokud nějaký jsou, tak to uloží do databáze.
Data v budoucnu chci zpracovávat pomocí AI. (Až se to líp naučím)
-
Jo, jinak v tom mém kodu mělo být
await asyncio.sleep(1)
a ne jen asyncio.sleep(1)
, ale na to sem přišel rychle, protože mi to dávalo warning.
-
Jenže teďka, když teda používám ten pyppeteer, jeden spuštěnej browser a 7 otevřenejch tabů, jejichž zdroják checkuju... Spuštěnejch procesů chrome je nějak o dost víc, asi 15-20, a load average je zhruba 3x vyšší.. resp. kolísá cca mezi 10-20.. ale chvilku byl i 50, lol..
Zkusil bych ty stranky zavirat pomoci page.close