

Web scraping to proces automatycznego wydobywania określonych danych z Internetu. Ma wiele zastosowań, takich jak pozyskiwanie danych do projektu uczenia maszynowego, tworzenie narzędzia do porównywania cen lub innego innowacyjnego pomysłu, który wymaga ogromnej ilości danych.
Chociaż teoretycznie można przeprowadzić ekstrakcję danych ręcznie, ogromna zawartość Internetu sprawia, że w wielu przypadkach takie podejście jest nierealne. Wiedza o tym, jak zbudować narzędzie do skrobania stron internetowych, może się przydać.
Celem tego artykułu jest nauczenie Cię, jak stworzyć narzędzie do skrobania stron internetowych w Pythonie. Dowiesz się, jak sprawdzić stronę internetową, aby przygotować się do scrapingu, wyodrębnić określone dane za pomocą BeautifulSoup, poczekać na renderowanie JavaScript za pomocą Selenium i zapisać wszystko w nowym pliku JSON lub CSV.
Ale najpierw powinienem cię ostrzec o legalności web scrapingu. Chociaż czynność skrobania jest legalna, dane, które możesz wyodrębnić, mogą być nielegalne w użyciu. Upewnij się, że nie zadzierasz z żadnym:
- Treść chroniona prawem autorskim – ponieważ jest czyjąś własnością intelektualną, jest chroniona prawem i nie można jej tak po prostu ponownie wykorzystać.
- Dane osobowe – jeśli zebrane przez Ciebie informacje mogą posłużyć do zidentyfikowania osoby, są uważane za dane osobowe, a dla obywateli UE są chronione na mocy RODO. Jeśli nie masz zgodnego z prawem powodu do przechowywania tych danych, lepiej po prostu je całkowicie pominąć.
Ogólnie rzecz biorąc, zawsze powinieneś przeczytać warunki witryny przed skrobaniem, aby upewnić się, że nie naruszasz ich zasad. Jeśli nie wiesz, jak postąpić, skontaktuj się z właścicielem witryny i poproś o zgodę.
Co będzie potrzebne do skrobaka?
Aby zacząć budować własny skrobak internetowy, najpierw musisz go miećPytonzainstalowany na twoim komputerze. Ubuntu 20.04 i inne wersje Linuksa są dostarczane z preinstalowanym Pythonem 3.
Aby sprawdzić, czy masz już zainstalowany Python na swoim urządzeniu, uruchom następujące polecenie:
python3 -v
Jeśli masz zainstalowany Python, powinieneś otrzymać taki wynik:
Pythona 3.8.2
Również dla naszego web scrapera użyjemy pakietów Pythona BeautifulSoup (do wybierania określonych danych) i Selenium (do renderowania dynamicznie ładowanej treści). Aby je zainstalować, po prostu uruchom te polecenia:
pip3 zainstaluj piękną zupę4
I
pip3 instaluje selen
Ostatnim krokiem jest upewnienie sięzainstaluj Google ChromeISterownik Chromena twojej maszynie. Będą one niezbędne, jeśli chcemy używać Selenium do scrapowania dynamicznie ładowanych treści.
Jak sprawdzić stronę
Teraz, gdy masz już wszystko zainstalowane, nadszedł czas, aby na poważnie rozpocząć nasz projekt skrobania.
Powinieneś wybrać witrynę, którą chcesz zeskrobać, w oparciu o swoje potrzeby. Pamiętaj, że każda witryna ma inną strukturę treści, więc musisz dostosować to, czego się tutaj nauczysz, kiedy zaczniesz samodzielnie skrobać. Każda strona będzie wymagała drobnych zmian w kodzie.
Na potrzeby tego artykułu postanowiłem zeskrobać informacje o pierwszych dziesięciu filmach z listy 250 najlepszych filmów z IMDb:https://www.imdb.com/chart/top/.
Najpierw uzyskamy tytuły, a następnie zagłębimy się dalej, wydobywając informacje ze strony każdego filmu. Niektóre dane będą wymagały renderowania JavaScript.
Aby zacząć rozumieć strukturę treści, należy kliknąć prawym przyciskiem myszy na pierwszy tytuł z listy, a następnie wybrać opcję „Sprawdź element”.
Naciskając CTRL+F i przeszukując strukturę kodu HTML, zobaczysz, że jest tylko jeden
Selektor HTML, który poda nam wszystkie tytuły ze strony totable tbody tr td.titleColumn a
. To dlatego, że wszystkie tytuły znajdują się w kotwicy wewnątrz komórki tabeli z klasą „titleColumn”.
Używanie tego selektora CSS i pobieranietekst wewnętrznykażdej kotwicy da nam tytuły, których potrzebujemy. Możesz to zasymulować w konsoli przeglądarki z nowo otwartego okna i używając linii JavaScript:
document.querySelectorAll("treść tabeli tr td.titleColumn a")[0].innerText
Zobaczysz coś takiego:
Teraz, gdy mamy ten selektor, możemy zacząć pisać nasz kod w Pythonie i wyodrębniać potrzebne informacje.
Jak używać BeautifulSoup do wyodrębniania zawartości ładowanej statycznie
Tytuły filmów z naszej listy są treściami statycznymi. To dlatego, że jeśli spojrzysz na źródło strony (CTRL + U na stronie lub kliknij prawym przyciskiem myszy, a następnie wybierz Wyświetl źródło strony), zobaczysz, że tytuły już tam są.
Treść statyczna jest zwykle łatwiejsza do zeskrobania, ponieważ nie wymaga renderowania JavaScript. Aby wyodrębnić pierwsze dziesięć tytułów z listy, użyjemy BeautifulSoup do pobrania zawartości, a następnie wydrukujemy ją na wyjściu naszego skrobaka.
import request from bs4 import BeautifulSoup page = request.get('https://www.imdb.com/chart/top/') # Pobieranie kodu HTML strony przez requestoup = BeautifulSoup(page.content, 'html.parser') # Parsowanie zawartości za pomocą beautifulsoup links = soup.select("table tbody tr td.titleColumn a") # Wybieranie wszystkich kotwic z tytułamifirst10 = links[:10] # Zachowaj tylko pierwszych 10 anchorsfor anchor in first10: print(anchor.text) # Wyświetla innerText każdej kotwicy
Powyższy kod używa selektora, który widzieliśmy w pierwszym kroku, aby wyodrębnić zakotwiczenia tytułu filmu ze strony. Następnie przechodzi przez pierwsze dziesięć i wyświetla tekst wewnętrzny każdego z nich.
Wyjście powinno wyglądać tak:
Jak wyodrębnić zawartość ładowaną dynamicznie
Wraz z rozwojem technologii strony internetowe zaczęły dynamicznie ładować swoje treści. Poprawia to wydajność strony, doświadczenie użytkownika, a nawet usuwa dodatkową barierę dla scraperów.
To jednak komplikuje sprawę, ponieważ kod HTML pobrany z prostego żądania nie będzie zawierał zawartości dynamicznej. Na szczęście dzięki Selenium możemy zasymulować żądanie w przeglądarce i czekać na wyświetlenie dynamicznej zawartości.
Jak używać Selenium do żądań
Musisz znać lokalizację swojego chromedrivera. Poniższy kod jest identyczny z tym przedstawionym w drugim kroku, ale tym razem używamy Selenium do wykonania żądania. Nadal będziemy analizować zawartość strony za pomocą BeautifulSoup, tak jak robiliśmy to wcześniej.
z bs4 import BeautifulSoupfrom selenium import webdriver option = webdriver.ChromeOptions()# Używam następujących opcji, ponieważ moja maszyna to podsystem okienkowy linux. # Zalecam przynajmniej użycie opcji headless spośród 3option.add_argument('--headless')option.add_argument('--no-sandbox')option.add_argument('--disable-dev-sh-usage')# RIVER', options=option) driver.get('https://www.imdb.com/chart/top/') # Pobieranie kodu HTML strony przez requestoup = BeautifulSoup(driver.page_source, 'html.parser') # Przetwarzanie treści przy użyciu beautifulsoup. Zwróć uwagę na driver.page_source zamiast page.content links = soup.select("table tbody tr td.titleColumn a") # Wybieranie wszystkich kotwic z tytułamifirst10 = links[:10] # Zachowaj tylko 10 pierwszych kotwic dla kotwicy w pierwszej 10: print(anchor.text) # Wyświetl wewnętrzny tekst każdej kotwicy
Nie zapomnij zastąpić „YOUR-PATH-TO-CHROMEDRIVER” lokalizacją, w której rozpakowałeś chromedriver. Należy również zauważyć, że zamiastzawartość strony
, kiedy tworzymy obiekt BeautifulSoup, którego teraz używamysterownik.źródło_strony
, który udostępnia zawartość HTML strony.
Jak wyodrębnić statycznie ładowaną zawartość za pomocą Selenium
Korzystając z powyższego kodu, możemy teraz uzyskać dostęp do każdej strony filmu, wywołując metodę click na każdej z kotwic.
first_link = driver.find_elements_by_css_selector('table tbody tr td.titleColumn a')[0]first_link.click()
Spowoduje to symulację kliknięcia linku do pierwszego filmu. Jednak w tym przypadku zalecam dalsze korzystaniedriver.get zamiast tego
. Dzieje się tak dlatego, że nie będziesz już mógł korzystać z usługiKliknij()
metody po przejściu na inną stronę, ponieważ nowa strona nie zawiera linków do pozostałych dziewięciu filmów.
W rezultacie, po kliknięciu na pierwszy tytuł z listy, trzeba by było wrócić na pierwszą stronę, następnie kliknąć na drugi i tak dalej. To strata wydajności i czasu. Zamiast tego użyjemy wyodrębnionych linków i uzyskamy do nich dostęp jeden po drugim.
Strona filmu „Skazani na Shawshank” będzie wyglądaćhttps://www.imdb.com/title/tt0111161/. Ze strony wyciągniemy rok i czas trwania filmu, ale tym razem jako przykład użyjemy funkcji Selenium zamiast BeautifulSoup. W praktyce możesz użyć jednego z nich, więc wybierz swój ulubiony.
Aby pobrać rok i czas trwania filmu, należy powtórzyć pierwszy krok, który przeszliśmy tutaj na stronie filmu.
Zauważysz, że możesz znaleźć wszystkie informacje w pierwszym elemencie z klasąipc-inline-list
(selektor „.ipc-inline-list”) i że wszystkie elementy listy zawierają ten atrybutrola
z wartościąprezentacja
(tzw[rola=’prezentacja’]
selektor).
z bs4 import BeautifulSoupfrom selenium import webdriver option = webdriver.ChromeOptions()# Używam następujących opcji, ponieważ moja maszyna to podsystem okienkowy linux. # Zalecam przynajmniej użycie opcji headless spośród 3option.add_argument('--headless')option.add_argument('--no-sandbox')option.add_argument('--disable-dev-sh-usage')# RIVER', options=option) page = driver.get('https://www.imdb.com/chart/top/') # Pobieranie HTML strony przez requestoup = BeautifulSoup(driver.page_source, 'html.parser') # Parsowanie treści za pomocą beautifulsoup totalScrapedInfo = [] # Na tej liście zapiszemy wszystkie informacje, które zapisujemy. s with titlesfirst10 = links[:10] # Zachowaj tylko pierwszych 10 kotwic w pierwszej 10: driver.get('https://www.imdb.com/' + anchor['href']) # Wejdź na stronę filmu infolist = driver.find_elements_by_css_selector('.ipc-inline-list')[0] # Znajdź pierwszy element z klasą „ipc-inline-list” informations = infolist.find_ elements_by_css_selector("[role='presentation']") # Znajdź wszystkie elementy z rolą='presentation' z pierwszego elementu z klasą 'ipc-inline-list' scrapedInfo = { "title": anchor.text, "year": informations[0].text, "duration": informations[2].text, } # Zapisz wszystkie zeskrobane informacje w słowniku totalScrapedInfo.append(scrapedInfo) # Dołącz słownik do totalScrapedIn formation list print(totalScrapedInfo) # Wyświetl listę ze wszystkimi zebranymi przez nas informacjami
Jak wyodrębnić dynamicznie ładowaną zawartość za pomocą Selenium
Kolejnym dużym krokiem w web scrapingu jest wyodrębnianie treści, która jest ładowana dynamicznie. Takie treści znajdziesz na każdej ze stron filmu (nphttps://www.imdb.com/title/tt0111161/) w sekcji Listy redakcyjne.
Jeśli spojrzysz na stronę za pomocą inspect, zobaczysz, że możesz znaleźć sekcję jako element z atrybutemtesty danych
ustawiony jakofirstListCardGroup-redakcja
. Ale jeśli zajrzysz do źródła strony, nigdzie nie znajdziesz tej wartości atrybutu. To dlatego, że sekcja list redakcyjnych jest ładowana dynamicznie przez IMDB.
W poniższym przykładzie zeskrobujemy listę redakcyjną każdego filmu i dodamy ją do naszych bieżących wyników wszystkich zeskrobanych informacji.
W tym celu zaimportujemy jeszcze kilka pakietów, które umożliwią oczekiwanie na załadowanie naszej zawartości dynamicznej.
z bs4 import BeautifulSoupfrom selen import webdriverfrom selenium.webdriver.common.by import Byfrom selenium.webdriver.support.ui import WebDriverWaitfrom selenium.webdriver.support import oczekiwane_warunki jako EC option = webdriver.ChromeOptions()# Używam następujących opcji, ponieważ mój komputer to podsystem okienkowy linux. # Zalecam przynajmniej użycie opcji headless spośród 3option.add_argument('--headless')option.add_argument('--no-sandbox')option.add_argument('--disable-dev-sh-usage')# RIVER', options=option) page = driver.get('https://www.imdb.com/chart/top/') # Pobieranie HTML strony przez requestoup = BeautifulSoup(driver.page_source, 'html.parser') # Parsowanie zawartości za pomocą beautifulsoup totalScrapedInfo = [] # Na tej liście zapiszemy wszystkie informacje, które zapisujemy. s with titlesfirst10 = links[:10] # Zachowaj tylko pierwszych 10 kotwic w pierwszej 10: driver.get('https://www.imdb.com/' + anchor['href']) # Wejdź na stronę filmu infolist = driver.find_elements_by_css_selector('.ipc-inline-list')[0] # Znajdź pierwszy element z klasą „ipc-inline-list” informations = infolist.find_ elements_by_css_selector("[role='presentation']") # Znajdź wszystkie elementy z rolą='presentation' z pierwszego elementu z klasą 'ipc-inline-list' scrapedInfo = { "title": anchor.text, "year": informations[0].text, "duration": informations[2].text, } # Zapisz wszystkie zeskrobane informacje w słowniku WebDriverWait(driver, 5).until(EC.visibility_of_element_located( (By.CSS_SELECTOR, "[data-testid='firstListCardGroup-editorial']"))) # Czekamy 5 sekund na nasz element z atrybutem data-testid ustawionym jako `firstListCardGroup-editorial` listElements = driver.find_elements_by_css_selector("[data-testid='firstListCardGroup-editorial'] .listName") # Wyodrębnianie elementów list redakcyjnych listNames = [] # Tworzenie pustej listy, a następnie dołączanie tylko tekstów elementów dla el w listElements: listNames.append(el.text) scrapedInfo['editorial-list'] = listNames # Dodanie nazw list redakcyjnych do naszego słownika scrapedInfo totalScrapedInfo.append(scrapedInfo) # Dołącz słownik do listy totalScrapedInformation print(totalScrapedInfo) # Wyświetl listę za pomocą wszystkie informacje, które wyskrobaliśmy
W poprzednim przykładzie powinieneś otrzymać następujące dane wyjściowe:
Jak zapisać zeskrobaną zawartość
Teraz, gdy mamy wszystkie potrzebne dane, możemy je zapisać jako plik .json lub .csv, aby były czytelniejsze.
Aby to zrobić, po prostu użyjemy pakietów JSON i CVS z Pythona i zapiszemy naszą zawartość do nowych plików:
import csvimport json ... file = open('movies.json', mode='w', encoding='utf-8')file.write(json.dumps(totalScrapedInfo)) writer = csv.writer(open("movies.csv", 'w')) dla filmu w totalScrapedInfo: writer.writerow(movie.values())
Wskazówki i porady dotyczące skrobania
Chociaż nasz przewodnik jest już wystarczająco zaawansowany, aby zająć się scenariuszami renderowania JavaScript, wciąż jest wiele rzeczy do odkrycia w Selenium.
W tej sekcji podzielę się kilkoma wskazówkami i sztuczkami, które mogą się przydać.
1. Zaplanuj swoje prośby
Jeśli spamujesz serwer setkami żądań w krótkim czasie, jest bardzo prawdopodobne, że w pewnym momencie pojawi się kod captcha lub nawet Twoje IP może zostać zablokowane. Niestety, w Pythonie nie ma obejścia, aby tego uniknąć.
Dlatego należy ustawić przerwy między kolejnymi żądaniami, aby ruch wyglądał bardziej naturalnie.
import timeimport request page = request.get('https://www.imdb.com/chart/top/') # Pobieranie kodu HTML strony przez requesttime.sleep(30) # Poczekaj 30 sekundpage = request.get('https://www.imdb.com/') # Pobieranie kodu HTML strony przez request
2. Obsługa błędów
Ponieważ strony internetowe są dynamiczne i mogą zmieniać strukturę w dowolnym momencie, obsługa błędów może się przydać, jeśli często korzystasz z tego samego web scrapera.
try: WebDriverWait(driver, 5).until(EC.presence_of_element_located((By.CSS_SELECTOR, "twój selektor"))) breakexcept TimeoutException: # Jeśli ładowanie trwało zbyt długo, wypisz wiadomość i spróbuj ponownie print("Ładowanie zajęło zbyt dużo czasu!")
Składnia prób i błędów może być przydatna, gdy czekasz na element, wyodrębniasz go, a nawet gdy tylko wysyłasz żądanie.
3. Zrób zrzuty ekranu
Jeśli w dowolnym momencie potrzebujesz zrzutu ekranu strony internetowej, którą przeglądasz, możesz użyć:
driver.save_screenshot('nazwa-pliku-zrzutu ekranu.png')
Może to pomóc w debugowaniu podczas pracy z dynamicznie ładowaną zawartością.
4. Przeczytaj dokumentację
Na koniec nie zapomnij przeczytaćdokumentacja z Selenium. Ta biblioteka zawiera informacje o tym, jak wykonać większość czynności, które można wykonać w przeglądarce.
Korzystając z Selenium, możesz wypełniać formularze, naciskać przyciski, odpowiadać na wyskakujące okienka i robić wiele innych fajnych rzeczy.
Jeśli napotkasz nowy problem, ich dokumentacja może być Twoim najlepszym przyjacielem.
Końcowe przemyślenia
Celem tego artykułu jest przedstawienie zaawansowanego wprowadzenia do web scrapingu przy użyciu Pythona z Selenium i BeautifulSoup. Chociaż nadal istnieje wiele funkcji obu technologii do zbadania, masz teraz solidną podstawę, jak rozpocząć skrobanie.
Czasami web scraping może być bardzo trudny, ponieważ strony zaczynają stawiać coraz więcej przeszkód na drodze programisty. Niektóre z tych przeszkód mogą stanowić kody Captcha, bloki adresów IP lub treści dynamiczne. Pokonanie ich tylko za pomocą Pythona i Selenium może być trudne lub wręcz niemożliwe.
Więc dam ci też alternatywę. Spróbuj użyć ainterfejs API skrobania sieciktóry rozwiązuje wszystkie te wyzwania za Ciebie. Wykorzystuje również rotacyjne serwery proxy, dzięki czemu nie musisz się martwić o dodawanie limitów czasu między żądaniami. Pamiętaj tylko, aby zawsze sprawdzać, czy żądane dane mogą być legalnie pozyskiwane i wykorzystywane.
REKLAMA
REKLAMA
REKLAMA
REKLAMA
REKLAMA
REKLAMA
REKLAMA
REKLAMA
REKLAMA
REKLAMA
REKLAMA
REKLAMA
REKLAMA

Jestem pasjonatem tworzenia stron internetowych z dużymi ambicjami, obecnie pracuję w JECO Technology nad projektami takimi jak WebScrapingAPI.
Jeśli ten artykuł był pomocny, .
Naucz się kodować za darmo. Program nauczania open source freeCodeCamp pomógł ponad 40 000 osób znaleźć pracę jako programiści.Zaczynaj
REKLAMA