Веб-парсинг — это процесс автоматического сбора данных с веб-сайтов для таких целей, как анализ данных или тонкая настройка моделей искусственного интеллекта.
Python является популярным выбором для веб-парсинга страниц благодаря обширному набору библиотек для парсинга, включая библиотеку lxml, которая используется для анализа документов XML и HTML. lxml расширяет возможности Python с помощью Python API для быстрых C-библиотек libxml2 и libxslt. Он также интегрируется с ElementTree, иерархической структурой данных Python для деревьев XML/HTML, что делает lxml предпочтительным инструментом для эффективного и надежного веб-парсинга.
Из этого руководства вы узнаете, как использовать lxml для веб-парсинга.
Решения Bright Data — идеальная альтернатива
В вопросах веб-парсинга, использование lxml с Python является эффективным подходом, но может занять много времени и средств, особенно при работе со сложными веб-сайтами или большими объемами данных. Bright Data предлагает эффективную альтернативу в виде своих готовых к использованию наборов данных и Web Scraper. Эти решения значительно сокращают время и затраты на сбор данных, предоставляя предварительно собранные данные из более чем 100 доменов и простые в интеграции API для парсинга.
С помощью Bright Data вы можете обойти технические трудности, связанные с ручным парсингом, и сосредоточиться на анализе данных, а не на их извлечении. Независимо от того, нужны ли вам наборы данных, адаптированные к вашим конкретным требованиям, или API, обеспечивающие управление прокси-серверами и решение капч, инструменты Bright Data предлагают оптимизированное и экономичное решение для всех ваших потребностей в веб-парсинге.
Использование lxml для веб-парсинга на Python
В Интернете структурированные и иерархические данные могут быть представлены в двух форматах — HTML и XML:
- XML — это базовая структура, которая не содержит готовых тегов и стилей. Программист создает структуру, определяя собственные теги. Основная цель тега — создать стандартную структуру данных, понятную для разных систем.
- HTML — это язык веб-разметки с предопределенными тегами. Эти теги обладают некоторыми свойствами стиля, такими как
font-size
в тегах<h1>
илиdisplay
для тегов<img />
. Основная функция HTML заключается в эффективном структурировании веб-страниц.
lxml работает как с документами HTML, так и с XML.
Предварительные условия
Прежде чем вы сможете начать веб-парсинг с помощью lxml, вам необходимо установить на ваш компьютер несколько библиотек:
pip install lxml requests cssselect
Эта команда устанавливает следующее:
- lxml для парсинга XML и HTML
- requests для загрузки веб-страниц
- cssselect, использующий CSS-селекторы для извлечения элементов HTML
Парсинг статического HTML-контента
Можно выполнять парсинг двух основных типов веб-контента: статического и динамического. Статический контент встраивается в HTML-документ при начальной загрузке веб-страницы, что упрощает его парсинг. Напротив, динамический контент загружается непрерывно или запускается JavaScript после начальной загрузки страницы. Для парсинга динамического контента необходимо указать время выполнения функции парсинга только после того, как контент станет доступен в браузере.
В этой статье вы начнете с парсинга сервиса Books to Scrape, на котором есть статический HTML-контент, предназначенный для тестирования. Вы извлекаете названия и цены книг и сохраняете эту информацию в виде файла JSON.
Для начала используйте Dev Tools браузера для определения соответствующих HTML-элементов. Откройте Dev Tools , щелкнув правой кнопкой мыши на веб-странице и выбрав опцию Inspect («Просмотреть код»). Если вы используете Chrome, вы можете нажать F12 , чтобы открыть это меню:
В правой части экрана отображается код, отвечающий за отображение страницы. Чтобы найти определенный HTML-элемент, обрабатывающий данные каждой книги, выполните поиск в коде, используя опцию выбора при наведении курсора мыши (стрелка в верхнем левом углу экрана):
В Dev Toolsвы должны увидеть следующий фрагмент кода:
<article class="product_pod">
<!-- code omitted -->
<h3><a href="catalogue/a-light-in-the-attic_1000/index.html" title="A Light in the Attic">A Light in the ...</a></h3>
<div class="product_price">
<p class="price_color">£51.77</p>
<!-- code omitted -->
</div>
</article>
В этом фрагменте каждая книга содержится в теге <article>
, помеченном классом product_pod
. Этот элемент предназначен для извлечения данных. Создайте новый файл с именем static_scrape.py
и добавьте следующий код:
import requests
from lxml import html
import json
URL = "https://books.toscrape.com/"
content = requests.get(URL).text
Этот код импортирует необходимые библиотеки и определяет переменную URL
. Он использует requests.get()
для получения статического HTML-контента веб-страницы путем отправки запроса GET на указанный URL-адрес. Затем HTML-код извлекается с использованием атрибута ответа text
.
Как только HTML-контент будет получен, вы выполните его парсинг с помощью lxml и извлечете необходимые данные. lxml предлагает два способа извлечения: XPath и CSS-селекторы. В этом примере вы используете XPath для получения названия книги и CSS-селекторы для получения цены книги.
Добавьте в скрипт следующий код:
parsed = html.fromstring(content)
all_books = parsed.xpath('//article[@class="product_pod"]')
books = []
Этот код инициализирует переменную, которая получена с помощью парсинга, содержит
html.fromstring(content)
и преобразует содержимое HTML в иерархическую древовидную структуру. Переменная all_books
использует селектор XPath для извлечения всех тегов <article>
с классом product_pod
с веб-страницы. Этот синтаксис особенно хорошо подходит для выражений XPath.
Затем добавьте в скрипт следующее, чтобы перебирать каждую книгу в all_books
и извлекать из нее данные:
for book in all_books:
book_title = book.xpath('.//h3/a/@title')
price = book.cssselect("p.price_color")[0].text_content()
books.append({"title": book_title, "price": price})
Переменная book_title
определяется с помощью селектора XPath, который извлекает атрибут title
из тега <a>
в теге <h3>
. Точка (.
) в начале выражения XPath указывает, что поиск следует начинать с тега <article>
, а не с начальной точки по умолчанию. В следующей строке метод cssselect
используется для извлечения цены из тега <p>
с классом price_color
. Поскольку cssselect
возвращает список, индексация ([0]
) обращается к первому элементу, а text_content()
извлекает текст из элемента. Каждая извлеченная пара заголовков и цен затем добавляется в список books
в виде словаря, который можно легко сохранить в файле JSON.
Теперь, когда вы завершили процесс веб-парсинга, пришло время сохранить эти данные локально. Откройте файл скрипта и введите следующий код:
with open("books.json", "w", encoding="utf-8") as file:
json.dump(books ,file)
В этом коде создается новый файл с именем books.json
. Этот файл заполняется с помощью метода json.dump
, который использует список books
в качестве источника и объект file
в качестве места назначения.
Вы можете протестировать этот скрипт, открыв терминал и выполнив следующую команду:
python static_scrape.py
Эта команда создает новый файл в вашем каталоге со следующим результатом:
Весь код этого скрипта доступен на GitHub.
Парсинг динамического HTML-контента
Парсинг динамического веб-контента сложнее, чем статического, поскольку JavaScript обрабатывает данные непрерывно, а не все сразу. Для парсинга динамического контента используйте инструмент автоматизации браузера под названием Selenium, который позволяет создавать и запускать экземпляр браузера, а также управлять им программно.
Чтобы установить Selenium, откройте терминал и выполните следующую команду:
pip install selenium
YouTube — отличный пример контента, отображаемого с помощью JavaScript. Когда вы заходите на любой канал, сначала загружается только ограниченное количество видео, а по мере прокрутки вниз появляется больше видео. Здесь вы собираете данные для ста лучших видео с канала FreeCodecamp.org на YouTube, эмулируя нажатия клавиш для прокрутки страницы.
Для начала изучите HTML-код веб-страницы. Когда вы откроете Dev Tools, вы увидите следующее:
Следующий код определяет элементы, отвечающие за отображение заголовка и ссылки на видео:
<a id="video-title-link" class="yt-simple-endpoint focus-on-expand style-scope ytd-rich-grid-media" href="/watch?v=i740xlsqxEM">
<yt-formatted-string id="video-title" class="style-scope ytd-rich-grid-media">GitHub Advanced Security Certification – Pass the Exam!
</yt-formatted-string></a>
Заголовок видео находится в теге yt-formated-string
с идентификатором video-title
, а ссылка на видео — в атрибуте href
тега a
с идентификатором video-title-link
.
Как только вы определите, парсинг чего хотите выполнить, создайте новый файл с именем dynamic_scrape.py
и добавьте следующий код, который импортирует все модули, необходимые для скрипта:
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from lxml import html
from time import sleep
import json
Здесь вы начнете с импорта webdriver
из selenium
, в результате чего создается экземпляр браузера, которым можно управлять программно. В следующих строках импортируются By
и Keys
, которые выбирают элемент в Интернете и нажимают на него несколькими клавишами. Функция sleep
импортируется, чтобы приостановить выполнение программы и дождаться, пока JavaScript отобразит содержимое на странице.
Отсортировав все импортированные данные, вы можете определить экземпляр драйвера для выбранного вами браузера. В этом руководстве используется Chrome, но Selenium также поддерживает Edge, Firefoxи Safari.
Чтобы определить экземпляр драйвера для браузера, добавьте скрипт со следующим кодом:
URL = "https://www.youtube.com/@freecodecamp/videos"
videos = []
driver = webdriver.Chrome()
driver.get(URL)
sleep(3)
Как и в предыдущем скрипте, вы указываете переменную URL
, содержащую URL-адрес веб-сайта, парсинг которого вы хотите выполнить, и переменную videos
, в которой все данные хранятся в виде списка. Затем объявляется переменная driver
(то есть экземплярChrome
), которую вы используете при взаимодействии с браузером. Функция get()
открывает экземпляр браузера и отправляет запрос на указанный URL
. После этого вы вызываете функцию sleep
, чтобы подождать три секунды, прежде чем получить доступ к любому элементу веб-страницы, чтобы убедиться, что весь HTML-код загружен в браузер.
Как упоминалось ранее, YouTube использует JavaScript для загрузки большего количества видео при прокрутке страницы вниз. Для парсинга данных из сотни видеороликов, после открытия браузера необходимо программно прокрутить страницу вниз. Это можно сделать, добавив в скрипт следующий код:
parent = driver.find_element(By.TAG_NAME, 'html')
for i in range(4):
parent.send_keys(Keys.END)
sleep(3)
В этом коде тег <html>
выбирается с помощью функции find_element
. Он возвращает первый элемент, соответствующий заданным критериям, которым в данном случае является тег html
. Метод send_keys
имитирует нажатие клавиши END
для прокрутки страницы вниз, что приводит к загрузке большего количества видео. Это действие повторяется четыре раза в цикле для
, чтобы обеспечить загрузку достаточного количества видео. Функция sleep
приостанавливается на три секунды после каждой прокрутки, чтобы видео могло загружаться, а затем снова прокручиваться.
Теперь, когда у вас есть все данные, необходимые для начала процесса парсинга, пора время использовать lxml с cssselect для выбора элементов, которые вы хотите извлечь:
html_data = html.fromstring(driver.page_source)
videos_html = html_data.cssselect("a#video-title-link")
for video in videos_html:
title = video.text_content()
link = "https://www.youtube.com" + video.get("href")
videos.append( {"title": title, "link": link} )
В этом коде содержимое HTML из атрибута драйвера page_source
передается в метод fromstring
, который создает иерархическое дерево HTML. Затем вы выбираете все теги <a>
с идентификатором video-title-link
с помощью селекторов CSS, где знак #
указывает на выбор с использованием идентификатора тега. Этот выбор возвращает список элементов, удовлетворяющих заданным критериям. Затем код перебирает каждый элемент, чтобы извлечь заголовок и ссылку. Метод text_content
извлекает внутренний текст (заголовок видео), а метод get
извлекает значение атрибута href
(ссылку на видео). Наконец, данные сохраняются в списке под названием videos
.
На этом процесс парсинга завершен. Следующий шаг заключается в локальном сохранении этих данных парсинга в вашей системе. Чтобы сохранить данные, добавьте следующий код в скрипт:
with open('videos.json', 'w') as file:
json.dump(videos, file)
driver.close()
Здесь вы создаете файл videos.json
и используете метод json.dump
для сериализации списка видео в формате JSON и записи его в объект файла. Наконец, вы вызываете метод close на объекте драйвера, чтобы безопасно закрыть и уничтожить экземпляр браузера.
Теперь вы можете протестировать свой скрипт, открыв терминал и выполнив следующую команду:
python dynamic_scrape.py
После запуска скрипта в вашем каталоге будет создан новый файл с именем videos.json
:
Весь код этого скрипта также доступен на GitHub.
Использование прокси-сервера Bright Data с lxml
Хотя веб-парсинг является отличным методом автоматизации сбора данных из различных источников, этот процесс не лишен проблем. Вам приходится сталкиваться с инструментами защиты от парсинга, внедренными на веб-сайтах, ограничениями скорости, геоблокировкой и отсутствием анонимности. Прокси-серверы могут помочь в решении этих проблем, выступая в роли посредников, маскирующих IP-адрес пользователя, что позволяет парсерам обходить ограничения и получать доступ к целевым данным незаметно. Bright Data — лучший выбор для надежных прокси-сервисов.
В следующем примере показано, насколько легко работать с прокси-серверами Bright Data. Это предполагает внесение некоторых изменений в файл script_scrape.py
для парсинга веб-сайта Books to Scrape.
Для начала вам необходимо получить прокси от Bright Data, подписавшись на бесплатную пробную версию, которая предоставляет прокси-ресурсы на сумму 5 $. После создания аккаунта Bright Data вы увидите следующую панель управления:
Перейдите к опции Мои зоны и создайте новую зону резидентного прокси. При создании новой зоны вы увидите имя пользователя, пароль и хост вашего прокси, которые вам понадобятся на следующем этапе.
Откройте файл static_scrape.py
и добавьте следующий код под переменной URL:
URL = "https://books.toscrape.com/"
# new
username = ""
password = ""
hostname = ""
proxies = {
"http": f"https://{username}:{password}@{hostname}",
"https": f"https://{username}:{password}@{hostname}",
}
content = requests.get(URL, proxies=proxies).text
Замените заполнители username
, password
и hostname
учетными данными прокси-сервера. Этот код предписывает библиотеке requests
использовать указанный прокси-сервер. Остальная часть скрипта остается без изменений.
Проверьте свой скрипт, выполнив следующую команду:
python static_scrape.py
После запуска этого скрипта вы увидите результат, аналогичный полученному в предыдущем примере.
Весь скрипт можно посмотреть на GitHub.
Заключение
lxml — это надежный и простой в использовании инструмент для извлечения данных из HTML-документов. lxml оптимизирован по скорости и поддерживает XPath и CSS-селекторы, что позволяет эффективно выполнять парсинг больших документов XML и HTML.
Из этого урока вы узнали все о веб-парсинге с помощью lxml и парсинге динамического и статического контента. Вы также узнали, как использование прокси-серверов Bright Data позволяет обойти ограничения, налагаемые веб-сайтами на использование парсеров.
Bright Data — это универсальное решение для всех ваших проектов по веб-парсингу. Оно предлагает такие функции, как прокси, браузеры для парсинга и разгадывание капч, которые позволяют пользователям эффективно решать проблемы веб-парсинга. У Bright Data также есть подробный блог с учебными пособиями и передовыми практиками веб-парсинга.
Хотите приступить к делу? Зарегистрируйтесь сейчас и протестируйте наши продукты бесплатно!
Кредитная карта не требуется