Автор оригинала: Sathiya Sarathi Gunasekaran.
Вступление
Веб-скребок-это программный сбор информации с различных веб-сайтов. В то время как существует множество библиотек и фреймворков на различных языках, которые могут извлекать веб-данные, Python уже давно является популярным выбором из-за его множества опций для веб-скрейпинга.
Эта статья даст вам ускоренный курс по веб – скрейпингу в Python с помощью BeautifulSoup – популярной библиотеки Python для синтаксического анализа HTML и XML.
Этическое Выскабливание паутины
Веб-скребок вездесущ и дает нам данные, которые мы получили бы с помощью API. Однако, как добропорядочные граждане Интернета, мы обязаны уважать владельцев сайтов, с которых мы соскребаем деньги. Вот некоторые принципы, которых должен придерживаться веб-скребок:
- Не претендуйте на соскобленный контент как на свой собственный. Владельцы веб – сайтов иногда тратят много времени на создание статей, сбор сведений о продуктах или сбор другого контента. Мы должны уважать их труд и оригинальность.
- Не царапайте сайт, который не хочет быть очищенным. Веб-сайты иногда поставляются с
robots.txt
файл – который определяет части веб-сайта, которые могут быть очищены. Многие веб-сайты также имеют Условия использования, которые могут не разрешать выскабливание. Мы должны уважать сайты, которые не хотят быть очищенными. - Есть ли уже доступный API? Великолепно, нам не нужно писать скребок. API-интерфейсы создаются для обеспечения доступа к данным контролируемым образом, определенным владельцами данных. Мы предпочитаем использовать API, если они доступны.
- Выполнение запросов на веб-сайт может привести к снижению производительности веб-сайта. Веб-скребок, который делает слишком много запросов, может быть таким же изнурительным, как и DDOS-атака. Мы должны скрести ответственно, чтобы не нарушить нормальное функционирование веб-сайта.
Обзор прекрасного супа
HTML-содержимое веб-страниц может быть проанализировано и очищено с помощью BeautifulSoup. В следующем разделе мы рассмотрим те функции, которые полезны для очистки веб-страниц.
Что делает Красивый суп таким полезным, так это множество функций, которые он предоставляет для извлечения данных из HTML. Это изображение ниже иллюстрирует некоторые из функций, которые мы можем использовать:
Давайте возьмемся за руки и посмотрим, как мы можем анализировать HTML с помощью BeautifulSoup. Рассмотрим следующую HTML – страницу, сохраненную в файл как doc.html
:
Следующие фрагменты кода тестируются на Ubuntu 20.04.1 LTS
. Вы можете установить модуль BeautifulSoup
, набрав в терминале следующую команду:
$ pip3 install beautifulsoup4
HTML-файл doc.html
нужно быть готовым. Это делается путем передачи файла в конструктор BeautifulSoup
, давайте использовать для этого интерактивную оболочку Python, чтобы мы могли мгновенно распечатать содержимое определенной части страницы:
from bs4 import BeautifulSoup with open("doc.html") as fp: soup = BeautifulSoup(fp, "html.parser")
Теперь мы можем использовать BeautifulSoup для навигации по нашему сайту и извлечения данных.
Переход к определенным тегам
Из объекта soup, созданного в предыдущем разделе, давайте получим тег заголовка doc.html
:
soup.head.title # returnsHead's title
Вот разбивка каждого компонента, который мы использовали для получения названия:
BeautifulSoup является мощным, потому что ваши объекты Python соответствуют вложенной структуре HTML-документа, который мы очищаем.
Чтобы получить текст первого тега , введите следующее:
soup.body.a.text # returns '1'
Чтобы получить заголовок в теге body HTML (обозначаемом классом “title”), введите в терминале следующее:
soup.body.p.b # returns Body's title
Для глубоко вложенных HTML-документов навигация может быстро стать утомительной. К счастью, Beautiful Soup поставляется с функцией поиска, поэтому нам не нужно перемещаться, чтобы получить HTML-элементы.
Поиск элементов тегов
Метод find_all()
принимает HTML-тег в качестве строкового аргумента и возвращает список элементов, совпадающих с предоставленным тегом. Например, если мы хотим, чтобы все a
теги были в doc.html
:
soup.find_all("a")
Мы увидим этот список тегов a
в качестве вывода:
Вот разбивка каждого компонента, который мы использовали для поиска тега:
Мы также можем искать теги определенного класса, предоставляя аргумент class_
. Beautiful Soup использует class_
потому что class
является зарезервированным ключевым словом в Python. Давайте поищем все теги a
, имеющие класс “элемент”:
soup.find_all("a", class_="element")
Поскольку у нас есть только две ссылки с классом “элемент”, вы увидите этот вывод:
Что делать, если мы хотим получить ссылки, встроенные в теги a
? Давайте получим атрибут ссылки href
с помощью опции find ()
. Он работает так же, как find_all ()
, но возвращает первый соответствующий элемент вместо списка. Введите это в свою оболочку:
soup.find("a", href=True)["href"] # returns http://example.com/element1
Функции find()
и find_all()
также принимают регулярное выражение вместо строки. За кулисами текст будет отфильтрован с помощью метода search()
скомпилированного регулярного выражения. Например:
import re for tag in soup.find_all(re.compile("^b")): print(tag)
Список после итерации извлекает теги, начинающиеся с символа b
, который включает в себя и
:
Мы рассмотрели самые популярные способы получения тегов и их атрибутов. Иногда, особенно для менее динамичных веб-страниц, нам просто нужен текст с них. Давайте посмотрим, как мы можем получить его!
Получение всего текста
Функция get_text()
извлекает весь текст из HTML-документа. Давайте получим весь текст HTML документа:
soup.get_text()
Ваш вывод должен быть таким:
Head's title Body's title line begins 1 2 3 line ends
Иногда печатаются символы новой строки, поэтому ваш вывод также может выглядеть следующим образом:
"\n\nHead's title\n\n\nBody's title\nline begins\n 1\n2\n3\n line ends\n\n"
Теперь, когда у нас есть представление о том, как использовать Красивый суп, давайте наскребем сайт!
Красивый суп в действии – Выскабливание списка книг
Теперь, когда мы освоили компоненты BeautifulSoup, пришло время применить наши знания на практике. Давайте построим скребок для извлечения данных из https://books.toscrape.com/ и сохраните его в CSV-файл. Сайт содержит случайные данные о книгах и является отличным местом для тестирования ваших методов веб-скребка.
Сначала создайте новый файл с именем scraper.py
. Давайте импортируем все библиотеки, которые нам нужны для этого скрипта:
import requests import time import csv import re from bs4 import BeautifulSoup
В модулях, упомянутых выше:
requests
– выполняет URL-запрос и извлекает HTML-код сайтаtime
– ограничивает, сколько раз мы выскабливаем страницу одновременноcsv
– помогает нам экспортировать наши очищенные данные в CSV-файлre
– позволяет писать регулярные выражения, которые пригодятся для подбора текста по его шаблонуbs4
– ваш покорный слуга, модуль выскабливания для разбора HTML
Вы бы уже установили bs4
, а time
, csv
и re
являются встроенными пакетами в Python. Вам нужно будет установить модуль requests
непосредственно следующим образом:
$ pip3 install requests
Прежде чем начать, вам нужно понять, как структурирован HTML – код веб-страницы. В вашем браузере давайте перейдем к http://books.toscrape.com/catalogue/page-1.html . Затем щелкните правой кнопкой мыши компоненты веб-страницы, подлежащей очистке, и нажмите кнопку inspect , чтобы понять иерархию тегов, как показано ниже.
Это покажет вам базовый HTML-код для того, что вы проверяете. На следующем рисунке показаны эти шаги:
Изучая HTML, мы узнаем, как получить доступ к URL-адресу книги, изображению обложки, названию, рейтингу, цене и другим полям из HTML. Давайте напишем функцию, которая очищает элемент книги и извлекает его данные:
def scrape(source_url, soup): # Takes the driver and the subdomain for concats as params # Find the elements of the article tag books = soup.find_all("article", class_="product_pod") # Iterate over each book article tag for each_book in books: info_url = source_url+"/"+each_book.h3.find("a")["href"] cover_url = source_url+"/catalogue" + \ each_book.a.img["src"].replace("..", "") title = each_book.h3.find("a")["title"] rating = each_book.find("p", class_="star-rating")["class"][1] # can also be written as : each_book.h3.find("a").get("title") price = each_book.find("p", class_="price_color").text.strip().encode( "ascii", "ignore").decode("ascii") availability = each_book.find( "p", class_="instock availability").text.strip() # Invoke the write_to_csv function write_to_csv([info_url, cover_url, title, rating, price, availability])
Последняя строка приведенного выше фрагмента указывает на функцию записи списка очищенных строк в CSV-файл. Давайте добавим эту функцию прямо сейчас:
def write_to_csv(list_input): # The scraped info will be written to a CSV here. try: with open("allBooks.csv", "a") as fopen: # Open the csv file. csv_writer = csv.writer(fopen) csv_writer.writerow(list_input) except: return False
Поскольку у нас есть функция, которая может очистить страницу и экспортировать ее в CSV, нам нужна другая функция, которая просматривает веб-сайт с разбиением на страницы, собирая данные книги на каждой странице.
Чтобы сделать это, давайте посмотрим на URL-адрес, для которого мы пишем этот скребок:
"http://books.toscrape.com/catalogue/page-1.html"
Единственным изменяющимся элементом в URL-адресе является номер страницы. Мы можем отформатировать URL-адрес динамически, чтобы он стал seed URL :
"http://books.toscrape.com/catalogue/page-{}.html".format(str(page_number))
Этот URL-адрес в формате строки с номером страницы можно получить с помощью метода requests.get()
. Затем мы можем создать новый объект BeautifulSoup
. Каждый раз, когда мы получаем объект супа, проверяется наличие кнопки “далее”, чтобы мы могли остановиться на последней странице. Мы отслеживаем счетчик для номера страницы, который увеличивается на 1 после успешного выскабливания страницы.
def browse_and_scrape(seed_url, page_number=1): # Fetch the URL - We will be using this to append to images and info routes url_pat = re.compile(r"(http://.*\.com)") source_url = url_pat.search(seed_url).group(0) # Page_number from the argument gets formatted in the URL & Fetched formatted_url = seed_url.format(str(page_number)) try: html_text = requests.get(formatted_url).text # Prepare the soup soup = BeautifulSoup(html_text, "html.parser") print(f"Now Scraping - {formatted_url}") # This if clause stops the script when it hits an empty page if soup.find("li", class_="next") != None: scrape(source_url, soup) # Invoke the scrape function # Be a responsible citizen by waiting before you hit again time.sleep(3) page_number += 1 # Recursively invoke the same function with the increment browse_and_scrape(seed_url, page_number) else: scrape(source_url, soup) # The script exits here return True return True except Exception as e: return e
Приведенная выше функция browse_and_scrape ()
рекурсивно вызывается до тех пор, пока функция soup.find("li", class_="next")
не вернет None
. В этот момент код очистит оставшуюся часть веб-страницы и выйдет.
Для последней части головоломки мы инициируем поток выскабливания. Мы определяем seed_url
и вызываем browse_and_scrape ()
, чтобы получить данные. Это делается под блоком if __name__
:
if __name__ == "__main__": seed_url = "http://books.toscrape.com/catalogue/page-{}.html" print("Web scraping has begun") result = browse_and_scrape(seed_url) if result == True: print("Web scraping is now complete!") else: print(f"Oops, That doesn't seem right!!! - {result}")
Если вы хотите узнать больше о блоке if __name__
, ознакомьтесь с нашим руководством по как он работает .
Вы можете выполнить сценарий, как показано ниже в вашем терминале, и получить вывод в виде:
$ python scraper.py
Web scraping has begun Now Scraping - http://books.toscrape.com/catalogue/page-1.html Now Scraping - http://books.toscrape.com/catalogue/page-2.html Now Scraping - http://books.toscrape.com/catalogue/page-3.html . . . Now Scraping - http://books.toscrape.com/catalogue/page-49.html Now Scraping - http://books.toscrape.com/catalogue/page-50.html Web scraping is now complete!
Очищенные данные можно найти в текущем рабочем каталоге под именем файла all Books.csv
. Вот пример содержимого файла:
http://books.toscrape.com/a-light-in-the-attic_1000/index.html,http://books.toscrape.com/catalogue/media/cache/2c/da/2cdad67c44b002e7ead0cc35693c0e8b.jpg,A Light in the Attic,Three,51.77,In stock http://books.toscrape.com/tipping-the-velvet_999/index.html,http://books.toscrape.com/catalogue/media/cache/26/0c/260c6ae16bce31c8f8c95daddd9f4a1c.jpg,Tipping the Velvet,One,53.74,In stock http://books.toscrape.com/soumission_998/index.html,http://books.toscrape.com/catalogue/media/cache/3e/ef/3eef99c9d9adef34639f510662022830.jpg,Soumission,One,50.10,In stock
Молодец! Если вы хотите взглянуть на код скребка в целом, вы можете найти его на GitHub .
Вывод
В этом уроке мы изучили этику написания хороших веб-скребков. Затем мы использовали BeautifulSoup для извлечения данных из HTML-файла, используя свойства объекта Beautifulsoup и его различные методы, такие как find ()
, find_all()
и get_text()
. Затем мы построили скребок, который извлекает список книг онлайн и экспортирует их в CSV.
Веб-скребок-это полезный навык, который помогает в различных действиях, таких как извлечение данных, таких как API, выполнение QA на веб-сайте, проверка неработающих URL-адресов на веб-сайте и многое другое. Какой следующий скребок вы собираетесь построить?