HTML is bijna intuïtief. CSS is een geweldige vooruitgang die de structuur van een pagina netjes van zijn uiterlijk en gevoel scheidt. JavaScript voegt wat pit toe. Dat is de theorie. De echte wereld is een beetje anders.
In deze zelfstudie leert u hoe de inhoud die u in de browser ziet, daadwerkelijk wordt weergegeven en hoe u deze kunt bijwerken wanneer dat nodig is. In het bijzonder leert u hoe u Disqus-opmerkingen kunt tellen. Onze hulpmiddelen zijn Python en geweldige pakketten zoals verzoeken, BeautifulSoup en Selenium.
Webscraping is de praktijk van het automatisch ophalen van de inhoud van webpagina's die zijn ontworpen voor interactie met menselijke gebruikers, het ontleden ervan en het extraheren van bepaalde informatie (eventueel het navigeren door koppelingen naar andere pagina's). Het is soms nodig als er geen andere manier is om de benodigde informatie te extraheren. In het ideale geval biedt de toepassing een speciale API voor het programmatisch toegang verkrijgen tot de gegevens. Er zijn verschillende redenen waarom webscraping je laatste redmiddel zou moeten zijn:
Laten we begrijpen waar we mee te maken hebben, door te kijken naar de uitvoer van een aantal veelgebruikte webtoepassingscode. In het artikel Inleiding tot Vagrant staan onderaan de pagina enkele Disqus-opmerkingen:
Om deze opmerkingen te schrappen, moeten we ze eerst op de pagina vinden.
Elke browser sinds het begin van de tijd (de jaren 90) heeft de mogelijkheid om de HTML van de huidige pagina te bekijken ondersteund. Hier is een fragment uit de weergavebron van Introductie tot Vagrant die begint met een groot deel van geminificeerd en niet-geëgaliseerd JavaScript dat geen verband houdt met het artikel zelf. Hier is een klein gedeelte ervan:
Hier is wat echte HTML van de pagina:
Dit ziet er nogal rommelig uit, maar wat verrassend is, is dat je de Disqus-opmerkingen niet zult vinden in de bron van de pagina.
Het is gebleken dat de pagina een mashup is en de Disqus-opmerkingen zijn ingesloten als een iframe (inline frame) element. U kunt dit achterhalen door met de rechtermuisknop op het gebied met opmerkingen te klikken en u zult zien dat er frame-informatie en bron daar is:
Dat is logisch. Het insluiten van inhoud van derden als een iframe is een van de belangrijkste redenen om iframes te gebruiken. Laten we het vinden tag dan in de bron van de hoofdpagina. Opnieuw verijdeld! Er is geen
tag in de bron van de hoofdpagina.
De reden voor deze omissie is dat Bekijk paginabron
toont u de inhoud die van de server is opgehaald. Maar de uiteindelijke DOM (document-objectmodel) die door de browser wordt weergegeven, kan heel verschillend zijn. JavaScript wordt ingeschakeld en kan naar eigen goeddunken de DOM manipuleren. Het iframe kan niet worden gevonden omdat het er niet was toen de pagina werd opgehaald van de server.
Statisch schrapen negeert JavaScript. Het haalt webpagina's van de server op zonder de hulp van een browser. Je krijgt precies wat je ziet in "bekijk paginabron", en dan snij je het in en snijd het. Als de inhoud die u zoekt beschikbaar is, hoeft u niet verder te gaan. Als de inhoud echter zoiets is als het Disqus-commentaar-iframe, hebt u dynamisch schrapen nodig.
Dynamisch schrapen maakt gebruik van een echte browser (of een headless browser) en laat JavaScript zijn gang gaan. Vervolgens vraagt hij de DOM om de inhoud te extraheren waarnaar hij op zoek is. Soms moet je de browser automatiseren door een gebruiker te simuleren om de inhoud te krijgen die je nodig hebt.
Laten we eens kijken hoe statisch schrapen werkt met behulp van twee geweldige Python-pakketten: aanvragen voor het ophalen van webpagina's en BeautifulSoup voor het parseren van HTML-pagina's.
Installeer eerst pipenv en dan: pipenv install requests beautifulsoup4
Dit zal ook een virtuele omgeving voor u creëren. Als je de code van gitlab gebruikt, kun je gewoon pipenv installeren
.
Een pagina met verzoeken ophalen is een voering: r = requests.get (url)
Het antwoordobject heeft veel attributen. De belangrijkste zijn OK
en inhoud
. Als het verzoek dan mislukt r.ok
is False en r.content
zal de fout bevatten. De inhoud is een stroom van bytes. Het is meestal beter om het te decoderen naar utf-8 als je te maken hebt met tekst:
>>> r = requests.get ('http://www.c2.com/no-such-page') >>> r.ok False >>> print (r.content.decode ('utf-8') ))404 Niet Gevonden Niet gevonden
De gevraagde URL / ggg is niet gevonden op deze server.
Apache / 2.0.52 (CentOS) Server op www.c2.com Poort 80
Als alles goed is dan r.content
zal de gevraagde webpagina bevatten (hetzelfde als bron van weergavepagina).
De get_page ()
functie hieronder haalt een webpagina op URL op, decodeert deze naar UTF-8 en parseert deze in een BeautifulSoup-object met behulp van de HTML-parser.
def get_page (url): r = requests.get (url) content = r.content.decode ('utf-8') return BeautifulSoup (inhoud, 'html.parser')
Zodra we een BeautifulSoup-object hebben, kunnen we beginnen met het extraheren van informatie van de pagina. BeautifulSoup biedt veel zoekfuncties om elementen op de pagina te vinden en diep geneste elementen te doorzoeken.
Tuts + auteurspagina's bevatten meerdere zelfstudies. Hier is mijn auteurspagina. Op elke pagina zijn er maximaal 12 zelfstudies. Als je meer dan 12 tutorials hebt, kun je naar de volgende pagina gaan. De HTML voor elk artikel is ingesloten in een label. De volgende functie vindt alle artikelelementen op de pagina, analyseert naar hun links en extraheert het href-kenmerk om de URL van de zelfstudie te krijgen:
def get_page_articles (page): elements = page.findAll ('article') articles = [e.a.attrs ['href'] voor e in elementen] retourneer artikelen
De volgende code haalt alle artikelen uit mijn pagina en drukt ze af (zonder het gewone voorvoegsel):
page = get_page ('https://tutsplus.com/authors/gigi-sayfan') articles = get_page_articles (pagina) prefix = 'https://code.tutsplus.com/tutorials' voor een in artikelen: print (a [ len (prefix):]) Uitgang: gebouw-games-met-python-3-en-pygame-deel-5 - cms-30085 gebouw-spellen-met-python-3-en-pygame-deel-4-- cms-30084 gebouw-spellen-met-python-3-en-pygame-deel-3 - cms-30083 gebouw-spellen-met-python-3-en-pygame-deel-2 - cms-30082 gebouw-spellen -with-python-3-and-pygame-part-1 - cms-30081 mastering-the-react-lifecycle-methods - cms-29849 testing-data-intensieve-code-met-go-deel-5-- cms-29852 testen-data-intensieve-code-met-go-deel-4 - cms-29851 testen-data-intensieve-code-met-gaan-deel-3 - cms-29850 testen-data-intensieve code -with-go-part-2 - cms-29848 testen-data-intensieve-code-met-gaan-deel-1 - cms-29847 make-the-go-programma's-bliksemsnelle-met-profilering-- cms-29809
Statisch schrapen was goed genoeg om de lijst met artikelen te krijgen, maar zoals we eerder zagen, zijn de Disqus-opmerkingen ingebed als een iframe-element door JavaScript. Om de opmerkingen te kunnen verzamelen, moeten we de browser automatiseren en interactief communiceren met de DOM. Een van de beste tools voor de klus is Selenium.
Selenium is primair gericht op het geautomatiseerd testen van webapplicaties, maar het is geweldig als een browserautomatiseringshulpmiddel voor algemene doeleinden.
Typ deze opdracht om Selenium te installeren: pipenv installeer selenium
Selenium heeft een webstuurprogramma nodig (de browser automatiseert dit). Voor webschrapen maakt het meestal niet uit welk stuurprogramma u kiest. Ik geef de voorkeur aan de Chrome-driver. Volg de instructies in deze Selenium-handleiding.
In sommige gevallen kunt u de voorkeur geven aan een headless-browser, wat betekent dat er geen gebruikersinterface wordt weergegeven. Theoretisch is PhantomJS gewoon een andere webdriver. Maar in de praktijk meldden mensen incompatibiliteitsproblemen waar Selenium goed werkt met Chrome of Firefox en soms faalt met PhantomJS. Ik geef er de voorkeur aan om deze variabele uit de vergelijking te verwijderen en een echte browser-webdriver te gebruiken.
Laten we wat dynamisch schrapen doen en Selenium gebruiken om Disqus-opmerkingen op Tuts + tutorials te tellen. Hier zijn de noodzakelijke invoer.
van selenium import webdriver van selenium.webdriver.common.by import Door van selenium.webdriver.support.expected_conditions import (presence_of_element_located) van selenium.webdriver.support.wait import WebDriverWait
De get_comment_count ()
functie accepteert een Selenium-stuurprogramma en URL. Het gebruikt de krijgen()
methode van het stuurprogramma om de URL op te halen. Dit is vergelijkbaar met requests.get ()
, maar het verschil is dat het object driver een live weergave van de DOM beheert.
Vervolgens krijgt het de titel van de zelfstudie en lokaliseert het Disqus iframe met behulp van de bovenliggende id disqus_thread
en dan het iframe zelf:
def get_comment_count (driver, url): driver.get (url) class_name = 'content-banner__title' name = driver.find_element_by_class_name (class_name) .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')
De volgende stap is om de inhoud van het iframe zelf op te halen. Merk op dat we wachten op de comment-count
element aanwezig omdat de opmerkingen dynamisch worden geladen en nog niet noodzakelijkerwijs beschikbaar zijn.
driver.get (iframe_url) wait = WebDriverWait (stuurprogramma, 5) commentCountPresent = presence_of_element_located ((By.CLASS_NAME, 'comment-count')) wait.until (commentCountPresent) comment_count_span = driver.find_element_by_class_name ('comment-count') comment_count = int (comment_count_span.text.split () [0])
Het laatste deel is om de laatste opmerking terug te sturen als deze niet door mij is gemaakt. Het idee is om opmerkingen te ontdekken waar ik nog niet op heb gereageerd.
last_comment = if comment_count> 0: e = driver.find_elements_by_class_name ('auteur') [- 1] last_author = e.find_element_by_tag_name ('a') last_author = e.get_attribute ('data-gebruikersnaam') als 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 (author = last_author, title = meta.get_attribute (' title '), when = meta.text) retourneer naam, comment_count, last_comment
Webscraping is een nuttige praktijk wanneer de informatie die u nodig hebt, toegankelijk is via een webtoepassing die geen geschikte API biedt. Het kost wat niet-triviaal werk om gegevens uit moderne webapplicaties te extraheren, maar volwassen en goed ontworpen tools zoals verzoeken, BeautifulSoup en Selenium maken het de moeite waard.
Aarzel ook niet om te zien wat we beschikbaar hebben voor de verkoop en om te studeren in de Envato-markt, en aarzel niet om vragen te stellen en uw waardevolle feedback te geven met behulp van de onderstaande feed.