HTML er nesten intuitivt. CSS er et flott fremskritt som skiller mellom strukturen på en side og utseende. JavaScript legger til noe pizazz. Det er teorien. Den virkelige verden er litt annerledes.
I denne opplæringen lærer du hvordan innholdet du ser i nettleseren, faktisk blir gjengitt og hvordan du skal skrape det når det er nødvendig. Spesielt lærer du hvordan du teller Disqus-kommentarer. Våre verktøy vil være Python og fantastiske pakker som forespørsler, BeautifulSoup og Selen.
Nettskraping er praksis for automatisk å hente innholdet på nettsider designet for samhandling med menneskelige brukere, parsing dem og utvinning av noen opplysninger (muligens navigere lenker til andre sider). Det er noen ganger nødvendig hvis det ikke er noen annen måte å trekke ut den nødvendige informasjonen. Ideelt sett gir applikasjonen en dedikert API for å få tilgang til dataene programmatisk. Det er flere grunner at nettskraping bør være din siste utvei:
La oss forstå hva vi står overfor, ved å se på utdataene fra noen vanlige webprogrammer. I artikkelen Introduksjon til Vagrant er det noen Disqus-kommentarer nederst på siden:
For å skrape disse kommentarene må vi finne dem på siden først.
Hver nettleser siden begynnelsen av tiden (1990-tallet) har støttet muligheten til å vise HTML-koden til gjeldende side. Her er en utdrag fra visningskilden Introduksjon til vagrant som starter med en stor del av sertifisert og uglified JavaScript uten tilknytning til selve artikkelen. Her er en liten del av det:
Her er noen HTML fra siden:
Dette ser ganske rotete ut, men det som er overraskende er at du ikke finner Disqus-kommentarene i kilden til siden.
Det viser seg at siden er en mashup, og Disqus-kommentarene er innebygd som et iframe (inline frame) -element. Du kan finne ut det ved å høyreklikke på kommentarfeltet, og du vil se at det er rammeinformasjon og kilde der:
Det er fornuftig. Inkludering av innhold fra tredjeparter som en iframe er en av de viktigste grunnene til å bruke iframes. La oss finne merk deretter på hovedsiden kilde. Foiled igjen! Det er ingen
tag på hovedsiden kilde.
Årsaken til dette utelatelsen er det Vis sidekilde
viser innholdet som ble hentet fra serveren. Men den endelige DOM (dokumentobjektmodellen) som blir gjengitt av nettleseren, kan være svært forskjellig. JavaScript sparker inn og kan manipulere DOM etter ønske. Iframe kan ikke bli funnet, fordi det ikke var der da siden ble hentet fra serveren.
Statisk skraping ignorerer JavaScript. Den henter websider fra serveren uten hjelp av en nettleser. Du får akkurat det du ser i "vise sidekilden", og så skjærer du det og taster det. Hvis innholdet du leter etter er tilgjengelig, trenger du ikke gå videre. Men hvis innholdet er noe som Disqus kommentarer iframe, trenger du dynamisk skraping.
Dynamisk skraping bruker en faktisk nettleser (eller en headless nettleser) og lar JavaScript gjøre det. Deretter spør den DOM for å trekke ut innholdet det leter etter. Noen ganger må du automatisere nettleseren ved å simulere en bruker for å få innholdet du trenger.
La oss se hvordan statisk skrap fungerer ved hjelp av to flotte Python-pakker: forespørsler om å hente websider og BeautifulSoup for å analysere HTML-sider.
Installer pipenv først, og deretter: pipenv installerer forespørsler beautifulsoup4
Dette vil skape et virtuelt miljø for deg også. Hvis du bruker koden fra gitlab, kan du bare pipenv installasjon
.
Å hente en side med forespørsler er en en liner: r = requests.get (url)
Svarobjektet har mange attributter. De viktigste er ok
og innhold
. Hvis forespørselen mislykkes da r.ok
vil være falsk og r.content
vil inneholde feilen. Innholdet er en strøm av byte. Det er vanligvis bedre å avkode det til utf-8 når det gjelder tekst:
>>> r = requests.get ('http://www.c2.com/no-such-page') >>> r.ok False >>> print (r.content.decode ('utf-8' ))404 ikke funnet Ikke funnet
Den forespurte nettadressen / ggg ble ikke funnet på denne serveren.
Apache / 2.0.52 (CentOS) Server på www.c2.com Port 80
Hvis alt er greit da r.content
vil inneholde den forespurte nettsiden (samme som visningskilden).
De get_page ()
funksjonen nedenfor henter en webside via URL, dekoder den til UTF-8, og analyserer den i et BeautifulSoup-objekt ved hjelp av HTML-parseren.
def get_page (url): r = requests.get (url) innhold = r.content.decode ('utf-8') returnere BeautifulSoup (innhold, 'html.parser')
Når vi har et BeautifulSoup-objekt, kan vi begynne å utvinne informasjon fra siden. BeautifulSoup gir mange funn for å finne elementer på siden og bore ned dype nestede elementer.
Tuts + forfattersider inneholder flere opplæringsprogrammer. Her er min forfatterside. På hver side er det opptil 12 opplæringsprogrammer. Hvis du har mer enn 12 opplæringsprogrammer, kan du navigere til neste side. HTML for hver artikkel er vedlagt i en stikkord. Følgende funksjon finner alle artikkelelementene på siden, driller seg ned til sine lenker, og trekker ut href-attributtet for å få nettadressen til opplæringen:
def get_page_articles (side): elements = page.findAll ('article') articles = [omtale ['href'] for e i elementer] returnere artikler
Følgende kode får alle artiklene fra siden min og skriver dem ut (uten vanlig prefiks):
side = get_page ('https://tutsplus.com/authors/gigi-sayfan') articles = get_page_articles (side) prefix = 'https://code.tutsplus.com/tutorials' for en i artikler: print (a [ len (prefiks):)) Output: building-games-med-python-3-og-pygame-del-5 - cms-30085 byggespill-med-python-3-og-pygame-del-4-- cms-30084 building-games-med-python-3-og-pygame-del-3 - cms-30083 byggespill-med-python-3-og-pygame-del-2 - cms-30082 byggespill -med-python-3-og-pygame-del-1 - cms-30081 mastering-the-react-lifecycle-metoder - cms-29849 test-data-intensiv-kode-med-gå-del-5-- cms-29852 test-data-intensiv kode-med-gå-del-4 - cms-29851 test-data-intensiv-kode-med-gå-del-3 - cms-29850 test-data-intensiv kode -with-go-part-2 - cms-29848 test-data-intensiv-kode-med-gå-del-1 - cms-29847 make-your-go-programmer-lynrask med profilering-- cms-29809
Statisk skraping var god nok til å få listen over artikler, men som vi så tidligere, er Disqus-kommentarene innebygd som et iframe-element av JavaScript. For å hente kommentarene må vi automatisere nettleseren og samhandle med DOM interaktivt. Et av de beste verktøyene for jobben er Selen.
Selen er primært rettet mot automatisert testing av webapplikasjoner, men det er flott som en generell nettleserautomatiseringsverktøy.
Skriv inn denne kommandoen for å installere Selen: pipenv installer selen
Selen trenger en webdriver (nettleseren automatiserer den). For nettskraping, spiller det ingen rolle hvilken sjåfør du velger. Jeg foretrekker Chrome-driveren. Følg instruksjonene i denne Selen-veiledningen.
I noen tilfeller kan du foretrekke å bruke en hovedlose nettleser, noe som betyr at ingen brukergrensesnitt vises. Teoretisk sett er PhantomJS bare en annen webdriver. Men i praksis rapporterte folk inkompatibilitetsproblemer der Selen fungerer riktig med Chrome eller Firefox og noen ganger mislykkes med PhantomJS. Jeg foretrekker å fjerne denne variabelen fra ligningen og bruke en faktisk nettleser web driver.
La oss gjøre noe dynamisk skraping og bruk Selen til å telle Disqus kommentarer på Tuts + opplæringsprogrammer. Her er den nødvendige importen.
fra selenimport webdriver fra selenium.webdriver.common.by import By fra selenium.webdriver.support.expected_conditions import (presence_of_element_located) fra selenium.webdriver.support.wait import WebDriverWait
De get_comment_count ()
funksjonen aksepterer en Seleni-driver og URL. Den bruker få()
Metoden for føreren å hente URL-adressen. Dette ligner på requests.get ()
, men forskjellen er at driverobjektet håndterer en levende representasjon av DOM.
Da blir det tittelen på opplæringen og lokaliserer Disqus iframe ved hjelp av foreldre-ID disqus_thread
og deretter iframe selv:
def get_comment_count (driver, url): driver.get (url) class_name = 'content-banner__title' name = driver.find_element_by_class_name (klassenavn) .text e = driver.find_element_by_id ('disqus_thread') disqus_iframe = e.find_element_by_tag_name ('iframe' ) iframe_url = disqus_iframe.get_attribute ('src')
Det neste trinnet er å hente innholdet av iframe selv. Legg merke til at vi venter på comment-count
element for å være til stede fordi kommentarene lastes dynamisk og ikke nødvendigvis tilgjengelig ennå.
driver.get (iframe_url) vent = WebDriverWait (driver, 5) commentCountPresent = presence_of_element_located ((By.CLASS_NAME, kommentar teller)) wait.until (commentCountPresent) comment_count_span = driver.find_element_by_class_name ('kommentar-count') comment_count = int (comment_count_span.text.split () [0])
Den siste delen er å returnere den siste kommentaren hvis den ikke ble gjort av meg. Tanken er å oppdage kommentarer jeg ikke har svart på ennå.
last_comment = hvis comment_count> 0: e = driver.find_elements_by_class_name ('author') [- 1] last_author = e.find_element_by_tag_name ('a') last_author = e.get_attribute ('data-brukernavn') if last_author! = ' the_gigi ': e = driver.find_elements_by_class_name (' post-meta ') meta = e [-1] .find_element_by_tag_name (' a ') last_comment = dict (forfatter = last_author, title = meta.get_attribute (' title '), når = meta.text) returnavn, comment_count, last_comment
Nettskraping er en nyttig praksis når informasjonen du trenger er tilgjengelig gjennom et webprogram som ikke gir en passende API. Det tar litt ikke-trivielt arbeid å trekke ut data fra moderne webapplikasjoner, men modne og godt utformede verktøy som forespørsler, BeautifulSoup og Selen gjør det verdt.
Ikke nøl med å se hva vi har tilgjengelig for salg og for studier i Envato Market, og ikke nøl med å stille spørsmål og gi din verdifulle tilbakemelding ved å bruke feedet under.