🐍 Самоучитель по Python для начинающих. Часть 17: Основы скрапинга и парсинга
Научимся извлекать данные из статического и динамического контента с помощью регулярных выражений, XPath, BeautifulSoup, MechanicalSoup и Selenium. В конце статьи – код 10 скриптов для скрапинга данных и изображений с Wikipedia, Habr, LiveLib, IMDb и TIOBE.
Веб-скрапинг – это процесс автоматического сбора информации из онлайн-источников. Для выбора нужных сведений из массива «сырых» данных, полученных в ходе скрапинга, нужна дальнейшая обработка – парсинг. В процессе парсинга выполняются синтаксический анализ, разбор и очистка данных. Результат парсинга – очищенные, упорядоченные, структурированные данные, представленные в формате, понятном конечному пользователю (или приложению).
Скрипты для скрапинга создают определенную нагрузку на сайт, с которого они собирают данные – могут, например, посылать чрезмерное количество GET запросов к серверу. Это одна из причин, по которой скрапинг относится к спорным видам деятельности. Чтобы не выходить за рамки сетевого этикета, необходимо всегда соблюдать главные правила сбора публичной информации:
- Если на сайте есть API, нужно запрашивать данные у него.
- Частота и количество GET запросов должны быть разумными.
- Следует передавать информацию о клиенте в
User-Agent
. - Если на сайте есть личные данные пользователей, необходимо учитывать настройки приватности в robots.txt.
Необходимо отметить, что универсальных рецептов скрапинга и парсинга не существует. Это связано со следующими причинами:
- Некоторые сервисы активно блокируют скраперов. Динамическая смена прокси не всегда помогает решить эту проблему.
- Контент многих современных сайтов генерируется динамически – результат обычного GET запроса из приложения к таким сайтам вернется практически пустым. Эта проблема решается с помощью Selenium WebDriver либо MechanicalSoup, которые имитируют действия браузера и пользователя.
Для извлечения данных со страниц с четкой, стандартной структурой эффективнее использовать язык запросов XPath. И напротив, для получения нужной информации с нестандартных страниц с произвольным синтаксисом лучше использовать средства библиотеки BeautifulSoup. Ниже мы подробно рассмотрим оба подхода.
Примеры скрапинга и парсинга на Python
Экосистема Python располагает множеством инструментов для скрапинга и парсинга. Начнем с самого простого примера – получения веб-страницы и извлечения из ее кода ссылки.
Скрапинг содержимого страницы
Воспользуемся модулем urllib.request стандартной библиотеки urllib для получения исходного кода одностраничного сайта example.com:
from urllib.request import urlopen url = 'http://example.com' page = urlopen(url) print(page.read().decode('utf-8'))
Результат:
<!doctype html> <html> <head> <title>Example Domain</title> <meta charset="utf-8" /> <meta http-equiv="Content-type" content="text/html; charset=utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <style type="text/css"> body { background-color: #f0f0f2; margin: 0; padding: 0; font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif; } div { width: 600px; margin: 5em auto; padding: 2em; background-color: #fdfdff; border-radius: 0.5em; box-shadow: 2px 3px 7px 2px rgba(0,0,0,0.02); } a:link, a:visited { color: #38488f; text-decoration: none; } @media (max-width: 700px) { div { margin: 0 auto; width: auto; } } </style> </head> <body> <div> <h1>Example Domain</h1> <p>This domain is for use in illustrative examples in documents. You may use this domain in literature without prior coordination or asking for permission.</p> <p><a href="https://www.iana.org/domains/example">More information...</a></p> </div> </body> </html>
Точно такой же результат можно получить с помощью requests:
from bs4 import BeautifulSoup import requests url = 'http://example.com' res = requests.get(url) soup = BeautifulSoup(res.text,'html.parser') print(soup)
Этот результат – те самые сырые данные, которые нужно обработать (подвергнуть парсингу), чтобы извлечь из них нужную информацию, например, адрес указанной на странице ссылки:
Парсинг полученных данных
Извлечь адрес ссылки можно 4 разными способами – с помощью:
- Методов строк.
- Регулярного выражения.
- Запроса XPath.
- Обработки BeautifulSoup.
Рассмотрим все эти способы по порядку.
Методы строк
Это самый трудоемкий способ – для извлечения каждого элемента нужно определить 2 индекса – начало и конец вхождения. При этом к индексу вхождения надо добавить длину стартового фрагмента:
from urllib.request import urlopen url = 'http://example.com/' page = urlopen(url) html_code = page.read().decode('utf-8') start = html_code.find('href="') + 6 end = html_code.find('">More') link = html_code[start:end] print(link)
Результат:
https://www.iana.org/domains/example
Регулярное выражение
В предыдущей главе мы подробно рассматривали способы извлечения конкретных подстрок из текста. Точно так же регулярные выражения можно использовать для поиска данных в исходном коде страниц:
from urllib.request import urlopen import re url = 'http://example.com/' page = urlopen(url) html_code = page.read().decode('utf-8') link = r'(https?://\S+)(?=")' print(re.findall(link, html_code))
Результат:
https://www.iana.org/domains/example
Запрос XPath
Язык запросов XPath (XML Path Language) позволяет извлекать данные из определенных узлов XML-документа. Для работы с HTML кодом в Python используют модуль etree:
from urllib.request import urlopen from lxml import etree url = 'http://example.com/' page = urlopen(url) html_code = page.read().decode('utf-8') tree = etree.HTML(html_code) print(tree.xpath("/html/body/div/p[2]/a/@href")[0])
Результат:
https://www.iana.org/domains/example
Чтобы узнать путь к нужному элементу страницы, в браузерах Chrome и FireFox надо кликнуть правой кнопкой по элементу и выбрать «Просмотреть код», после чего откроется консоль. В консоли по интересующему элементу нужно еще раз кликнуть правой кнопкой, выбрать «Копировать», а затем – копировать путь XPath:
В приведенном выше примере для извлечения ссылки к пути
/html/body/div/p[2]/a/
мы добавили указание для получения значения ссылки @href
,
и индекс [0]
, поскольку результат возвращается в виде списка. Если @href
заменить на text()
, программа вернет текст ссылки, а не сам URL:
print(tree.xpath("/html/body/div/p[2]/a/text()")[0])
Результат:
More information...
Парсер BeautifulSoup
Регулярные выражения и XPath предоставляют огромные возможности для извлечения нужной информации из кода страниц, но у них есть свои недостатки: составлять Regex-шаблоны сложно, а запросы XPath хорошо работают только на страницах с безупречной, стандартной структурой. К примеру, страницы Википедии не отличаются идеальной структурой, и использование XPath для извлечения нужной информации из определенных элементов статей, таких как таблицы infobox, часто оказывается неэффективным. В этом случае оптимальным вариантом становится BeautifulSoup, специально разработанный для парсинга HTML-кода.
Библиотека BeautifulSoup не входит в стандартный набор Python, ее нужно установить самостоятельно:
pip install beautifulsoup4
В приведенном ниже примере мы будем извлекать из исходного кода страницы уникальные ссылки, за исключением внутренних:
from bs4 import BeautifulSoup from urllib.request import urlopen url = 'https://webscraper.io/test-sites/e-commerce/allinone/phones' page = urlopen(url) html = page.read().decode('utf-8') soup = BeautifulSoup(html, 'html.parser') links = set() for link in soup.find_all('a'): l = link.get('href') if l != None and l.startswith('https'): links.add(l) for link in links: print(link)
Результат:
https://twitter.com/webscraperio https://www.facebook.com/webscraperio/ https://forum.webscraper.io/ https://webscraper.io/downloads/Web_Scraper_Media_Kit.zip https://cloud.webscraper.io/ https://chrome.google.com/webstore/detail/web-scraper/jnhgnonknehpejjnehehllkliplmbmhn?hl=en
При использовании XPath точно такой же результат даст следующий скрипт:
from urllib.request import urlopen from lxml import etree url = 'https://webscraper.io/test-sites/e-commerce/allinone/phones' page = urlopen(url) html_code = page.read().decode('utf-8') tree = etree.HTML(html_code) sp = tree.xpath("//li/a/@href") links = set() for link in sp: if link.startswith('http'): links.add(link) for link in links: print(link)
Имитация действий пользователя в браузере
При скрапинге сайтов очень часто требуется авторизация, нажатие кнопок «Читать дальше», переход по ссылкам, отправка форм, прокручивание ленты и так далее. Отсюда возникает необходимость имитации действий пользователя. Как правило, для этих целей используют Selenium, однако есть и более легкое решение – библиотека MechanicalSoup:
pip install MechanicalSoup
По сути, MechanicalSoup исполняет роль браузера без графического интерфейса. Помимо имитации нужного взаимодействия с элементами страниц, MechanicalSoup также парсит HTML-код, используя для этого все функции BeautifulSoup.
Воспользуемся тестовым сайтом http://httpbin.org/, на котором есть возможность отправки формы заказа пиццы:
import mechanicalsoup browser = mechanicalsoup.StatefulBrowser() browser.open("http://httpbin.org/") browser.follow_link("forms") browser.select_form('form[action="/post"]') print(browser.form.print_summary())
В приведенном выше примере браузер MechanicalSoup перешел по внутренней ссылке http://httpbin.org/forms/post и вернул описание полей ввода:
<input name="custname"/> <input name="custtel" type="tel"/> <input name="custemail" type="email"/> <input name="size" type="radio" value="small"/> <input name="size" type="radio" value="medium"/> <input name="size" type="radio" value="large"/> <input name="topping" type="checkbox" value="bacon"/> <input name="topping" type="checkbox" value="cheese"/> <input name="topping" type="checkbox" value="onion"/> <input name="topping" type="checkbox" value="mushroom"/> <input max="21:00" min="11:00" name="delivery" step="900" type="time"/> <textarea name="comments"></textarea> <button>Submit order</button>
Перейдем к имитации заполнения формы:
browser["custname"] = "Best Customer" browser["custtel"] = "+7 916 123 45 67" browser["custemail"] = "trex@example.com" browser["size"] = "large" browser["topping"] = ("cheese", "mushroom") browser["comments"] = "Add more cheese, plz. More than the last time!"
Теперь форму можно отправить:
response = browser.submit_selected()
Результат можно вывести с помощью print(response.text)
:
{ "args": {}, "data": "", "files": {}, "form": { "comments": "Add more cheese, plz. More than the last time!", "custemail": "trex@example.com", "custname": "Best Customer", "custtel": "+7 916 123 45 67", "delivery": "", "size": "large", "topping": [ "cheese", "mushroom" ] }, "headers": { "Accept": "*/*", "Accept-Encoding": "gzip, deflate", "Content-Length": "191", "Content-Type": "application/x-www-form-urlencoded", "Host": "httpbin.org", "Referer": "http://httpbin.org/forms/post", "User-Agent": "python-requests/2.28.1 (MechanicalSoup/1.2.0)", "X-Amzn-Trace-Id": "Root=1-6404d82d-2a9ae95225dddaec1968ccb8" }, "json": null, "origin": "86.55.39.89", "url": "http://httpbin.org/post" }
Скрапинг и парсинг динамического контента
Все примеры, которые мы рассмотрели выше, отлично работают на статических страницах. Однако на множестве платформ используется динамический подход к генерации и загрузке контента – к примеру, для просмотра всех доступных товаров в онлайн-магазине страницу нужно не только открыть, но и прокрутить до футера. Для работы с динамическим контентом в Python нужно установить:
- Модуль Selenium.
- Драйвер Selenium WebDriver для браузера.
Если установка прошла успешно, выполнение этого кода приведет к автоматическому открытию страницы:
from selenium import webdriver driver = webdriver.Chrome() # или webdriver.Firefox() driver.get('https://google.com')
Бывает, что даже после установки оптимальной версии драйвера
интерпретатор Python возвращает ошибку OSError: [WinError 216] Версия
"%1" не совместима с версией Windows
. В этом случае нужно
воспользоваться модулем webdriver-manager, который самостоятельно
установит подходящий драйвер для нужного браузера:
from selenium import webdriver from selenium.webdriver.chrome.service import Service as ChromeService from webdriver_manager.chrome import ChromeDriverManager driver = webdriver.Chrome(service=ChromeService(ChromeDriverManager().install()))
Имитация прокрутки страницы и парсинг данных
В качестве примера скрапинга и парсинга динамического сайта мы воспользуемся разделом тестового онлайн-магазина. Здесь расположены карточки с информацией о планшетах. Карточки загружаются ряд за рядом при прокрутке страницы:
Пока страница не прокручена, полный HTML-код с информацией о планшетах
получить невозможно. Для имитации прокрутки мы воспользуемся скриптом 'window.scrollTo(0,
document.body.scrollHeight);'
. Цены планшетов находятся в тегах h4 класса pull-right price, а
названия моделей – в тексте ссылок a класса title. Готовый код
выглядит так:
from selenium import webdriver from selenium.webdriver.chrome.service import Service as ChromeService from webdriver_manager.chrome import ChromeDriverManager import time from bs4 import BeautifulSoup driver = webdriver.Chrome(service=ChromeService(ChromeDriverManager(cache_valid_range=10).install())) url = 'https://webscraper.io/test-sites/e-commerce/scroll/computers/tablets' driver.get(url) driver.execute_script('window.scrollTo(0, document.body.scrollHeight);') time.sleep(5) html = driver.page_source soup = BeautifulSoup(html, 'html.parser') prices = soup.find_all('h4', class_='pull-right price') models = soup.find_all('a', class_='title') for model, price in zip(models, prices): m = model.get_text() p = price.get_text() print(f'Планшет {m}, цена - {p}')
Результат:
Планшет Lenovo IdeaTab, цена - $69.99 Планшет IdeaTab A3500L, цена - $88.99 Планшет Acer Iconia, цена - $96.99 Планшет Galaxy Tab 3, цена - $97.99 Планшет Iconia B1-730HD, цена - $99.99 Планшет Memo Pad HD 7, цена - $101.99
Практика
Задание 1
Напишите программу для получения названий последних статей из блога издательства O’Reilly:
Пример результата:
Sydney and the Bard What Does Copyright Say about Generative Models? Technology Trends for 2023 Radar Trends to Watch: February 2023
Решение:
from bs4 import BeautifulSoup import requests url = 'https://www.oreilly.com/radar/' headers = {"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36"} res = requests.get(url, headers=headers) soup = BeautifulSoup(res.text,'html.parser') sp = soup.find_all('h2', class_='post-title') for post in sp: print(post.get_text())
Задание 2
Напишите программу для определения 10 слов, которые чаще всего встречаются в тексте сказки «Колобок» (без учета регистра). Предлоги учитывать не нужно.
Ожидаемый результат:
колобок - 32 ушел - 14 тебя - 7 коробу - 6 сусеку - 6 сметане - 5 масле - 5 покатился - 4 катится - 4 навстречу - 4
Решение:
from bs4 import BeautifulSoup import requests import re url = 'https://azku.ru/russkie-narodnie-skazki/kolobok.html' res = requests.get(url) soup = BeautifulSoup(res.text,'html.parser') res = soup.find_all('div', class_='entry-content') text = res[0].get_text().split('Мне нравится')[0] sp = re.sub(r'[-,.?!"—:]', ' ', text).lower().split() result_dict = {word: sp.count(word) for word in sp if len(word) > 3} max_values = sorted(result_dict.items(), key=lambda x:x[1], reverse=True)[:10] for word, number in max_values: print(f'{word} - {number}')
Задание 3
Напишите программу, которая на основе данных таблицы создает список цитат из фильмов, выпущенных после 1995 года.
Ожидаемый результат:
Show me the money! Покажи мне деньги! Род Тидвелл Кьюба Гудинг мл. Джерри Магуайер 1996 I see dead people. Я вижу мёртвых людей. Коул Сиэр Хэйли Джоэл Осмент Шестое чувство 1999 You had me at 'hello'. Я была твоя уже на «здрасьте». Дороти Бойд Рене Зеллвегер Джерри Магуайер 1996 My precious. Моя прелесть. Голлум Энди Серкис Властелин колец: Две крепости 2002 I’m the king of the world! Я король мира! Джек Доусон Леонардо Ди Каприо Титаник 1997
Решение:
from bs4 import BeautifulSoup import requests import re url = 'https://ru.wikipedia.org/wiki/100_%D0%B8%D0%B7%D0%B2%D0%B5%D1%81%D1%82%D0%BD%D1%8B%D1%85_%D1%86%D0%B8%D1%82%D0%B0%D1%82_%D0%B8%D0%B7_%D0%B0%D0%BC%D0%B5%D1%80%D0%B8%D0%BA%D0%B0%D0%BD%D1%81%D0%BA%D0%B8%D1%85_%D1%84%D0%B8%D0%BB%D1%8C%D0%BC%D0%BE%D0%B2_%D0%B7%D0%B0_100_%D0%BB%D0%B5%D1%82_%D0%BF%D0%BE_%D0%B2%D0%B5%D1%80%D1%81%D0%B8%D0%B8_AFI' res = requests.get(url).text soup = BeautifulSoup(res,'html.parser') table = soup.find('table', class_='wikitable') header = table.find_all('th') quotes = table.find_all('tr') quotes_after_1995 = [] for i in range(1, len(quotes)): q = quotes[i].get_text() if int(q[-5:]) > 1995: quotes_after_1995.append(' '.join(q.split('\n\n')[1:]).replace('\n', '')) for quote in quotes_after_1995: print(quote)
Задание 4
Напишите программу, которая извлекает данные о моделях, конфигурации и стоимости 117-ти ноутбуков, и записывает полученную информацию в csv файл.
Ожидаемый результат:
Модель;Описание;Цена Asus VivoBook X441NA-GA190;Asus VivoBook X441NA-GA190 Chocolate Black, 14", Celeron N3450, 4GB, 128GB SSD, Endless OS, ENG kbd;$295.99 ... Asus ROG Strix SCAR Edition GL503VM-ED115T;Asus ROG Strix SCAR Edition GL503VM-ED115T, 15.6" FHD 120Hz, Core i7-7700HQ, 16GB, 256GB SSD + 1TB SSHD, GeForce GTX 1060 6GB, Windows 10 Home;$1799.00
Решение:
from bs4 import BeautifulSoup import requests url = 'https://webscraper.io/test-sites/e-commerce/allinone/computers/laptops' res = requests.get(url) soup = BeautifulSoup(res.text,'html.parser') models = soup.find_all('a', class_='title') description = soup.find_all('p', class_='description') prices = soup.find_all('h4', class_='pull-right price') with open('laptops.csv', 'w', encoding='utf-8') as file: file.write(f'Модель;Описание;Цена\n') for m, d, p in zip(models, description, prices): file.write(f"{m['title']};{d.get_text()};{p.get_text()}\n")
Задание 5
Напишите программу для скачивания полноразмерных обложек из профилей книг на LiveLib. Обложки открываются после двойного клика по миниатюре:
Решение:
from bs4 import BeautifulSoup import requests import re url = 'https://www.livelib.ru/book/1002978643-ohotnik-za-tenyu-donato-karrizi' headers = {"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36"} res = requests.get(url, headers=headers) soup = BeautifulSoup(res.text,'html.parser') sp = soup.find('div', class_='bc-menu__image-wrapper') img_url = re.findall(r'(?:https\:)?//.*\.(?:jpeg)', str(sp))[0] response = requests.get(img_url, headers=headers) if response.status_code == 200: file_name = url.split('-', 1)[1] with open(file_name + '.jpeg', 'wb') as file: file.write(response.content)
Задание 6
Напишите программу, которая составляет рейтинг топ-100 лучших триллеров на основе этого списка.
Пример результата:
1. "Побег из Шоушенка", Стивен Кинг - 4.60 2. "Заживо в темноте", Майк Омер - 4.50 3. "Молчание ягнят", Томас Харрис - 4.47 4. "Девушка с татуировкой дракона", Стиг Ларссон - 4.42 5. "Внутри убийцы", Майк Омер - 4.38 ... 98. "Абсолютная память", Дэвид Болдаччи - 4.22 99. "Сломанные девочки", Симона Сент-Джеймс - 4.11 100. "Цифровая крепость", Дэн Браун - 3.98
Решение:
from bs4 import BeautifulSoup import requests url = 'https://www.livelib.ru/genre/%D0%A2%D1%80%D0%B8%D0%BB%D0%BB%D0%B5%D1%80%D1%8B/top' headers = {"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36"} res = requests.get(url, headers=headers) soup = BeautifulSoup(res.content,'html.parser') titles = soup.find_all('a', class_='brow-book-name with-cycle') authors = soup.find_all('a', class_='brow-book-author') rating = soup.find_all('span', class_='rating-value stars-color-orange') i = 1 for t, a, r in zip(titles, authors, rating): print(f'{i}. "{t.get_text()}", {a.get_text()} - {r.get_text()}') i += 1
Задание 7
Напишите программу, которая составляет топ-20 языков программирования на основе рейтинга популярности TIOBE.
Пример результата:
1. Python: 14.83% 2. C: 14.73% 3. Java: 13.56% 4. C++: 13.29% 5. C#: 7.17% 6. Visual Basic: 4.75% 7. JavaScript: 2.17% 8. SQL: 1.95% 9. PHP: 1.61% 10. Go: 1.24% 11. Assembly language: 1.11% 12. MATLAB: 1.08% 13. Delphi/Object Pascal: 1.06% 14. Scratch: 1.00% 15. Classic Visual Basic: 0.98% 16. R: 0.93% 17. Fortran: 0.79% 18. Ruby: 0.76% 19. Rust: 0.73% 20. Swift: 0.71%
Решение:
import requests from lxml import html url = 'https://www.tiobe.com/tiobe-index/' headers = {"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36"} page = requests.get(url, headers=headers) tree = html.fromstring(page.content) languages, rating = [], [] for i in range(1, 21): languages.append(tree.xpath(f'//*[@id="top20"]/tbody/tr[{i}]/td[5]/text()')[0]) rating.append(tree.xpath(f'//*[@id="top20"]/tbody/tr[{i}]/td[6]/text()')[0]) i = 1 for l, r in zip(languages, rating): print(f'{i}. {l}: {r}') i += 1
Задание 8
Напишите программу для получения рейтинга 250 лучших фильмов по версии IMDb. Названия должны быть на русском языке.
Пример результата:
1. Побег из Шоушенка, (1994), 9,2 2. Крестный отец, (1972), 9,2 3. Темный рыцарь, (2008), 9,0 ... 248. Аладдин, (1992), 8,0 249. Ганди, (1982), 8,0 250. Танцующий с волками, (1990), 8,0
Решение:
import requests from lxml import html url = 'https://www.imdb.com/chart/top/' headers = {"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36", "Accept-Language": "ru-RU"} page = requests.get(url, headers=headers) tree = html.fromstring(page.content) movies, year, rating = [], [], [] for i in range(1, 251): movies.append(tree.xpath(f'//*[@id="main"]/div/span/div/div/div[3]/table/tbody/tr[{i}]/td[2]/a/text()')[0]) year.append(tree.xpath(f'//*[@id="main"]/div/span/div/div/div[3]/table/tbody/tr[{i}]/td[2]/span/text()')[0]) rating.append(tree.xpath(f'//*[@id="main"]/div/span/div/div/div[3]/table/tbody/tr[{i}]/td[3]/strong/text()')[0]) i = 1 for m, y, r in zip(movies, year, rating): print(f'{i}. {m}, {y}, {r}') i += 1
Задание 9
Напишите программу, которая сохраняет в текстовый файл данные о фэнтези фильмах с 10 первых страниц соответствующего раздела IMDb. Если у фильма/сериала еще нет рейтинга, следует указать N/A.
Ожидаемый результат в файле fantasy.txt – 500 записей:
Мандалорец, (2019– ), 8,7 Всё везде и сразу, (2022), 8,0 Атака титанов, (2013–2023), 9,0 Peter Pan & Wendy, (2023), N/A Игра престолов, (2011–2019), 9,2 ... Шрэк 3, (2007), 6,1 Кунг-фу Панда 3, (2016), 7,1 Смерть ей к лицу, (1992), 6,6 Исход: Цари и боги, (2014), 6,0 Кошмар на улице Вязов 3: Воины сна, (1987), 6,6
Решение:
import requests import mechanicalsoup from lxml import html import time url = 'https://www.imdb.com/search/title/?genres=fantasy' headers = {"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36", "Accept-Language": "ru-RU"} browser = mechanicalsoup.StatefulBrowser() j = 51 for _ in range(10): browser.open(url) page = requests.get(url, headers=headers) tree = html.fromstring(page.content) titles, year, rating = [], [], [] for i in range(1, 51): if tree.xpath(f'//*[@id="main"]/div/div[3]/div/div[{i}]/div[3]/p[1]/b/text()') != []: titles.append(tree.xpath(f'//*[@id="main"]/div/div[3]/div/div[{i}]/div[3]/h3/a/text()')[0]) year.append(tree.xpath(f'//*[@id="main"]/div/div[3]/div/div[{i}]/div[3]/h3/span[2]/text()')[0]) rating.append('N/A') else: titles.append(tree.xpath(f'//*[@id="main"]/div/div[3]/div/div[{i}]/div[3]/h3/a/text()')[0]) year.append(tree.xpath(f'//*[@id="main"]/div/div[3]/div/div[{i}]/div[3]/h3/span[2]/text()')[0]) rating.append(tree.xpath(f'//*[@id="main"]/div/div[3]/div/div[{i}]/div[3]/div/div[1]/strong/text()')[0]) with open('fantasy.txt', 'a', encoding='utf-8') as file: for t, y, r in zip(titles, year, rating): file.write(f'{t}, {y}, {r}\n') time.sleep(2) lnk = browser.follow_link('start=' + str(j)) url = browser.url j += 50
Задание 10
Напишите программу для получения главных новостей (на русском) с портала Habr. Каждый заголовок должен сопровождаться ссылкой на полный текст новости.
Пример вывода:
Bethesda назвала дату релиза Starfield на ПК, Xbox Series и Xbox Game Pass — 6 сентября 2023 года https://habr.com/ru/news/t/721148/ Honda запатентовала съёмные подушки безопасности для мотоциклистов https://habr.com/ru/news/t/721142/ ... Microsoft увольняет 689 сотрудников из своих офисов в Сиэтле https://habr.com/ru/news/t/721010/ «Ъ»: в России образовались большие запасы бытовой техники из-за низкого спроса https://habr.com/ru/news/t/721006/
Решение:
from bs4 import BeautifulSoup import requests url = 'https://habr.com/ru/news/' headers = {"User-Agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.96 Safari/537.36", "Accept-Language": "ru-RU"} res = requests.get(url, headers=headers) soup = BeautifulSoup(res.content,'html.parser') articles = soup.find_all('a', class_='tm-article-snippet__title-link') for a in articles: print(f'{a.get_text()}\nhttps://habr.com{a.get("href")}')
Заключение
Мы рассмотрели основные приемы работы с главными Python-инструментами для скрапинга и парсинга. Способы извлечения и обработки данных варьируются от сайта к сайту – в некоторых случаях эффективнее использование XPath, в других – разбор с BeautifulSoup, а иногда может потребоваться применение регулярных выражений.
В следующей главе приступим к изучению основ ООП (объектно-ориентированного программирования).
Содержание самоучителя
- Особенности, сферы применения, установка, онлайн IDE
- Все, что нужно для изучения Python с нуля – книги, сайты, каналы и курсы
- Типы данных: преобразование и базовые операции
- Методы работы со строками
- Методы работы со списками и списковыми включениями
- Методы работы со словарями и генераторами словарей
- Методы работы с кортежами
- Методы работы со множествами
- Особенности цикла for
- Условный цикл while
- Функции с позиционными и именованными аргументами
- Анонимные функции
- Рекурсивные функции
- Функции высшего порядка, замыкания и декораторы
- Методы работы с файлами и файловой системой
- Регулярные выражения
- Основы скрапинга и парсинга
- Основы ООП – инкапсуляция и наследование
- Основы ООП – абстракция и полиморфизм
- Графический интерфейс на Tkinter
- Основы разработки игр на Pygame
- Основы работы с SQLite
- Основы веб-разработки на Flask
- Основы работы с NumPy
- Основы анализа данных с Pandas