HTML är nästan intuitivt. CSS är en stor framsteg som tydligt skiljer strukturen på en sida från dess utseende. JavaScript lägger till lite pizazz. Det är teorin. Den verkliga världen är lite annorlunda.
I den här handledningen lär du dig hur innehållet du ser i webbläsaren faktiskt görs och hur du ska skrapa om det behövs. I synnerhet lär du dig att räkna Disqus kommentarer. Våra verktyg kommer att vara Python och fantastiska paket som förfrågningar, BeautifulSoup och Selen.
Webbskrapning är praxis att automatiskt hämta innehållet på webbsidor som är utformade för interaktion med mänskliga användare, analysera dem och extrahera viss information (eventuellt navigera länkar till andra sidor). Det är ibland nödvändigt om det inte finns något annat sätt att extrahera nödvändig information. Idealt sett tillhandahåller programmet ett dedikerat API för att få tillgång till dess data programmerat. Det finns flera anledningar att webbskrapning borde vara din sista utväg:
Låt oss förstå vad vi står inför, genom att titta på produktionen av en vanlig gemensam webbapplikationskod. I artikeln Introduktion till Vagrant finns det några Disqus-kommentarer längst ner på sidan:
För att skrapa dessa kommentarer måste vi hitta dem på sidan först.
Varje webbläsare sedan början av 1990-talet har stödt möjligheten att visa HTML på den aktuella sidan. Här är ett utdrag ur visningskällan Introduktion till Vagrant som börjar med en stor bit av minifierad och uglified JavaScript som inte är relaterad till själva artikeln. Här är en små del av det:
Här är en viss HTML från sidan:
Det här ser ganska rörigt ut, men det som förvånar är att du inte hittar Disqus-kommentarerna i källan till sidan.
Det visar sig att sidan är en mashup, och Disqus-kommentarerna är inbäddade som en iframe (inline frame) -element. Du kan ta reda på det genom att högerklicka på kommentarfältet och du ser att det finns raminformation och källa där:
Det låter vettigt. Inbäddning av innehåll från tredje part som iframe är en av de främsta anledningarna till att använda iframes. Låt oss hitta tag sedan på huvudsidans källa. Foiled igen! Det finns inget
taggen i huvudsidans källa.
Anledningen till detta utelämnande är det Visa sidans källa
visar innehållet som hämtats från servern. Men den slutliga DOM (dokumentobjektmodellen) som görs av webbläsaren kan vara mycket annorlunda. JavaScript sparkar in och kan manipulera DOM efter vilja. Iframe kan inte hittas, eftersom det inte var där när sidan hämtades från servern.
Statisk skrap ignorerar JavaScript. Den hämtar webbsidor från servern utan hjälp av en webbläsare. Du får exakt det du ser i "visa sidkälla", och sedan skär du och tärningar det. Om innehållet du söker är tillgängligt, behöver du inte gå längre. Men om innehållet är något som Disqus kommentarer iframe behöver du dynamisk skrapning.
Dynamisk skrapning använder en faktisk webbläsare (eller en huvudlös webbläsare) och låter JavaScript göra sin sak. Sedan frågar den DOM för att extrahera innehållet det letar efter. Ibland behöver du automatisera webbläsaren genom att simulera en användare för att få innehållet du behöver.
Låt oss se hur statisk skrapning fungerar med två fantastiska Python-paket: förfrågningar om att hämta webbsidor och BeautifulSoup för att analysera HTML-sidor.
Installera pipenv först och sedan: pipenv installerar begär beautifulsoup4
Detta skapar en virtuell miljö för dig också. Om du använder koden från gitlab kan du bara pipenv installation
.
Att hämta en sida med förfrågningar är en enda liner: r = requests.get (url)
Svarobjektet har många attribut. De viktigaste är ok
och innehåll
. Om förfrågan misslyckas då r.ok
kommer att vara falskt och r.content
kommer att innehålla felet. Innehållet är en ström av byte. Det är vanligtvis bättre att avkoda det till utf-8 när man hanterar text:
>>> r = requests.get ('http://www.c2.com/no-such-page') >>> r.ok False >>> print (r.content.decode ('utf-8' ))404 Ej Hittad Hittades inte
Den begärda webbadressen / ggg kunde inte hittas på den här servern.
Apache / 2.0.52 (CentOS) Server på www.c2.com Port 80
Om allt är OK då r.content
kommer att innehålla den begärda webbsidan (samma som sidkälla).
De get_page ()
funktionen nedan hämtar en webbsida via URL, avkodar den till UTF-8 och analyserar den i ett BeautifulSoup-objekt med hjälp av HTML-parsern.
def get_page (url): r = requests.get (url) content = r.content.decode ('utf-8') returnera BeautifulSoup (content, 'html.parser')
När vi har ett BeautifulSoup-objekt kan vi börja extrahera information från sidan. BeautifulSoup ger många funktionsfunktioner för att hitta element inuti sidan och borra ner djupt inbäddade element.
Tuts + författarsidor innehåller flera handledning. Här är min författarsida. På varje sida finns det upp till 12 handledning. Om du har mer än 12 handledningar kan du navigera till nästa sida. HTML för varje artikel är bifogad i en märka. Följande funktion hittar alla artikelelement på sidan, övningar ner till sina länkar och extraherar href-attributet för att få webbadressen till handledningen:
def get_page_articles (sida): elements = page.findAll ('article') articles = [bland annat ['href'] för e i element] returnera artiklar
Följande kod får alla artiklar från min sida och skriver ut dem (utan det gemensamma prefixet):
page = get_page ('https://tutsplus.com/authors/gigi-sayfan') articles = get_page_articles (sida) prefix = 'https://code.tutsplus.com/tutorials' för en i artiklar: print (a [ len (prefix):)) Output: building-games-with-python-3-and-pygame-part-5 - cms-30085 bygg-spel-med-python-3-och-pygame-del-4-- cms-30084 bygg-spel-med-python-3-och-pygame-del-3 - cms-30083 bygg-spel-med-python-3-och-pygame-del-2 - cms-30082 byggnadsspel -med-python-3-och-pygam-del-1-cms-30081 mastering-the-react-lifecycle-metoderna - cms-29849 test-data-intensiv-kod-med-gå-del-5-- cms-29852 test-data-intensiv kod-med-gå-del-4 - cms-29851 test-data-intensiv kod-med-gå-del-3 - cms-29850 test-data-intensiv kod -med-gå-del-2 - cms-29848 test-data-intensiv-kod-med-gå-del-1 - cms-29847 gör-din-gå-program-blixt-snabb-med-profilering-- cms-29809
Statisk skrapning var tillräckligt bra för att få listan över artiklar, men som vi såg tidigare, är Disqus-kommentarerna inbäddade som ett iframe-element med JavaScript. För att skörda kommentarerna måste vi automatisera webbläsaren och interagera med DOM interaktivt. Ett av de bästa verktygen för jobbet är Selen.
Selen är främst inriktat på automatiserad testning av webbapplikationer, men det är bra som ett allmänt brukbart webbläsarautomatiseringsverktyg.
Skriv det här kommandot för att installera Selen: pipenv installer selen
Selen behöver en webdrivrutin (webbläsaren automatiserar den). För webbskrapning spelar det ingen roll vilken chaufför du väljer. Jag föredrar Chrome-drivrutinen. Följ anvisningarna i denna Selen guide.
I vissa fall kanske du föredrar att använda en huvudlös webbläsare, vilket innebär att inget användargränssnitt visas. Teoretiskt är PhantomJS bara en annan webbdrivrutin. Men i praktiken rapporterade personer oförenlighetsproblem där Selen fungerar korrekt med Chrome eller Firefox och ibland misslyckas med PhantomJS. Jag föredrar att ta bort den här variabeln från ekvationen och använd en webbläsare med webbläsare.
Låt oss göra lite dynamisk skrapning och använd Selen för att räkna Disqus kommentarer på Tuts + tutorials. Här är den nödvändiga importen.
från selen importera webdriver från selenium.webdriver.common.by import By från selenium.webdriver.support.expected_conditions import (presence_of_element_located) från selenium.webdriver.support.wait import WebDriverWait
De get_comment_count ()
funktionen accepterar en Selena-drivrutin och URL. Den använder skaffa sig()
Metod för föraren att hämta webbadressen. Detta liknar requests.get ()
, men skillnaden är att förarobjektet hanterar en live-representation av DOM.
Då blir det titeln på handledningen och lokaliserar Disqus iframe med dess föräldra id disqus_thread
och då iframen själv:
def get_comment_count (drivrutin, url): driver.get (url) class_name = 'content-banner__title' name = driver.find_element_by_class_name (klassnamn) .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')
Nästa steg är att hämta innehållet i iframe själv. Observera att vi väntar på kommentar-count
element att vara närvarande eftersom kommentarerna laddas dynamiskt och inte nödvändigtvis tillgängliga än.
driver.get (iframe_url) vänta = WebDriverWait (drivrutin, 5) commentCountPresent = presence_of_element_located ((By.CLASS_NAME, "kommentarräkning")) wait.until (commentCountPresent) comment_count_span = driver.find_element_by_class_name ('comment count') comment_count = int (comment_count_span.text.split () [0])
Den sista delen är att returnera den sista kommentaren om den inte gjordes av mig. Tanken är att upptäcka kommentarer jag inte har svarat på än.
last_comment = om 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-användarnamn') 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 (författare = last_author, title = meta.get_attribute (' title '), när = meta.text) returnera namn, comment_count, last_comment
Webbskrapning är en användbar praxis när den information du behöver är tillgänglig via en webbapplikation som inte tillhandahåller ett lämpligt API. Det tar lite otrevligt arbete att extrahera data från moderna webbapplikationer, men mogna och väl utformade verktyg som förfrågningar, BeautifulSoup och Selen gör det värt.
Tveka inte heller att se vad vi har till salu och studera på Envato Market, och tveka inte att ställa några frågor och ge din värdefulla feedback genom att använda foderet nedan.