Автор оригинала: André Jaenisch.
Веб-соскреб – это процесс извлечения данных с веб-сайтов.
Прежде чем пытаться высказать веб-сайт, вы должны убедиться, что провайдер позволяет ему в своих условиях обслуживания. Вы также должны проверить, можете ли вы использовать вместо этого API.
Массивный соскоб может поставить сервер под болью напряжением, которое может привести к отрицанию сервиса. И ты этого не хочешь.
Кто должен прочитать это?
Эта статья для продвинутых читателей. Предположим, что вы уже знакомы с языком программирования Python.
На самом минимуме вы должны понимать список пониманий, контекстно-менеджер и функции. Вы также должны знать, как настроить виртуальную среду.
Мы запустим код на локальной машине, чтобы исследовать некоторые сайты. С некоторыми настройками вы могли бы сделать его и на сервере.
Что вы узнаете в этой статье
В конце этой статьи вы будете знать, как скачать веб-страницу, разбирать его для интересной информации и отформатировать его в используемый формат для дальнейшей обработки. Это также известно как ETL Отказ
Эта статья также объяснит, что делать, если этот веб-сайт использует JavaScript для визуализации контента (например, rance.js или ingular).
Предпосылки
Прежде чем я смогу начать, я хочу убедиться, что мы готовы к работе. Пожалуйста, настройте виртуальную среду и установите в нее следующие пакеты:
- BeautifulSoup4 (версия 4.9.0 во время написания)
- Запросы (версия 2.23.0 во время написания)
- WordCloud (версия 1.17.0 во время написания, необязательно)
- Селен (версия 3.141.0 во время написания, необязательно)
Вы можете найти код для этого проекта в этом Git Repository на Github Отказ
Для этого примера мы собираемся соскребать Основной закон для Федеративной Республики Германия Отказ (Не волнуйтесь, я проверил свои условия обслуживания. Они предлагают XML-версию для обработки машины, но эта страница служит примером обработки HTML. Так что должно быть в порядке.)
Шаг 1: Загрузите источник
Первые вещи первыми: я создаю файл URLS.TXT
Удерживая все URL-адреса, которые я хочу скачать:
https://www.gesetze-im-internet.de/gg/art_1.html https://www.gesetze-im-internet.de/gg/art_2.html https://www.gesetze-im-internet.de/gg/art_3.html https://www.gesetze-im-internet.de/gg/art_4.html https://www.gesetze-im-internet.de/gg/art_5.html https://www.gesetze-im-internet.de/gg/art_6.html https://www.gesetze-im-internet.de/gg/art_7.html https://www.gesetze-im-internet.de/gg/art_8.html https://www.gesetze-im-internet.de/gg/art_9.html https://www.gesetze-im-internet.de/gg/art_10.html https://www.gesetze-im-internet.de/gg/art_11.html https://www.gesetze-im-internet.de/gg/art_12.html https://www.gesetze-im-internet.de/gg/art_12a.html https://www.gesetze-im-internet.de/gg/art_13.html https://www.gesetze-im-internet.de/gg/art_14.html https://www.gesetze-im-internet.de/gg/art_15.html https://www.gesetze-im-internet.de/gg/art_16.html https://www.gesetze-im-internet.de/gg/art_16a.html https://www.gesetze-im-internet.de/gg/art_17.html https://www.gesetze-im-internet.de/gg/art_17a.html https://www.gesetze-im-internet.de/gg/art_18.html https://www.gesetze-im-internet.de/gg/art_19.html
Далее я пишу немного кода Python в файле под названием Scraper.py
Для загрузки HTML из этого файлов.
В реальном сценарии это было бы слишком дорого, и вместо этого использовали базу данных. Чтобы сохранить вещи простыми, я скачу файлы в тот же каталог рядом с магазином и используете их имя в качестве имени файла.
from os import path from pathlib import PurePath import requests with open('urls.txt', 'r') as fh: urls = fh.readlines() urls = [url.strip() for url in urls] # strip `\n` for url in urls: file_name = PurePath(url).name file_path = path.join('.', file_name) text = '' try: response = requests.get(url) if response.ok: text = response.text except requests.exceptions.ConnectionError as exc: print(exc) with open(file_path, 'w') as fh: fh.write(text) print('Written to', file_path)
Загрузив файлы, я могу обработать их локально столько, сколько я хочу, не будучи зависимым от сервера. Постарайтесь быть хорошим гражданином, хорошо?
Шаг 2: анализ источника
Теперь, когда я скачал файлы, пришло время извлечь свои интересные функции. Поэтому я иду на одну из страниц, которые я загрузил, открываю его в веб-браузере и нажмите Ctrl-u для просмотра его источника. Проверка, это покажет мне структуру HTML.
В моем случае я подумал, что хочу текст закона без какой-либо разметки. Обогащая элемент у него есть идентификатор Контейнер
Отказ Используя BeautifulSoup, я вижу, что комбинация Найти
и get_text сделаю то, что хочу.
Так как у меня сейчас есть второй шаг, я немного решакторую код, надевая его в функции и добавляю минимальную CLI.
from os import path from pathlib import PurePath import sys from bs4 import BeautifulSoup import requests def download_urls(urls, dir): paths = [] for url in urls: file_name = PurePath(url).name file_path = path.join(dir, file_name) text = '' try: response = requests.get(url) if response.ok: text = response.text else: print('Bad response for', url, response.status_code) except requests.exceptions.ConnectionError as exc: print(exc) with open(file_path, 'w') as fh: fh.write(text) paths.append(file_path) return paths def parse_html(path): with open(path, 'r') as fh: content = fh.read() return BeautifulSoup(content, 'html.parser') def download(urls): return download_urls(urls, '.') def extract(path): return parse_html(path) def transform(soup): container = soup.find(id='container') if container is not None: return container.get_text() def load(key, value): d = {} d[key] = value return d def run_single(path): soup = extract(path) content = transform(soup) unserialised = load(path, content.strip() if content is not None else '') return unserialised def run_everything(): l = [] with open('urls.txt', 'r') as fh: urls = fh.readlines() urls = [url.strip() for url in urls] paths = download(urls) for path in paths: print('Written to', path) l.append(run_single(path)) print(l) if __name__ == "__main__": args = sys.argv if len(args) is 1: run_everything() else: if args[1] == 'download': download([args[2]]) print('Done') if args[1] == 'parse': path = args[2] result = run_single(path) print(result)
Теперь я могу запустить код тремя способами:
- Без каких-либо аргументов запускать все (то есть загрузить все URL-адреса и извлечь их, а затем сохранить на диск) через:
Python Scraper.py.
- С аргументом
Скачать
и URL для скачиванияPython Scraper.py Скачать https://www.gesetze-im-internet.de/gg/art_1.html
Отказ Это не будет обработать файл. - С аргументом
Разбор
И FilePath для Parse:python scraper.py art_1.html
Отказ Это будет пропустить шаг загрузки.
С этим есть последняя вещь отсутствует.
Шаг 3: Формат источника для дальнейшей обработки
Допустим, я хочу создать слово облако для каждой статьи. Это может быть быстрый способ получить представление о том, о чем текст. Для этого установите пакет WordCloud
И обновить такой файл:
from os import path from pathlib import Path, PurePath import sys from bs4 import BeautifulSoup import requests from wordcloud import WordCloud STOPWORDS_ADDENDUM = [ 'Das', 'Der', 'Die', 'Diese', 'Eine', 'In', 'InhaltsverzeichnisGrundgesetz', 'im', 'Jede', 'Jeder', 'Kein', 'Sie', 'Soweit', 'Über' ] STOPWORDS_FILE_PATH = 'stopwords.txt' STOPWORDS_URL = 'https://raw.githubusercontent.com/stopwords-iso/stopwords-de/master/stopwords-de.txt' def download_urls(urls, dir): paths = [] for url in urls: file_name = PurePath(url).name file_path = path.join(dir, file_name) text = '' try: response = requests.get(url) if response.ok: text = response.text else: print('Bad response for', url, response.status_code) except requests.exceptions.ConnectionError as exc: print(exc) with open(file_path, 'w') as fh: fh.write(text) paths.append(file_path) return paths def parse_html(path): with open(path, 'r') as fh: content = fh.read() return BeautifulSoup(content, 'html.parser') def download_stopwords(): stopwords = '' try: response = requests.get(STOPWORDS_URL) if response.ok: stopwords = response.text else: print('Bad response for', url, response.status_code) except requests.exceptions.ConnectionError as exc: print(exc) with open(STOPWORDS_FILE_PATH, 'w') as fh: fh.write(stopwords) return stopwords def download(urls): return download_urls(urls, '.') def extract(path): return parse_html(path) def transform(soup): container = soup.find(id='container') if container is not None: return container.get_text() def load(filename, text): if Path(STOPWORDS_FILE_PATH).exists(): with open(STOPWORDS_FILE_PATH, 'r') as fh: stopwords = fh.readlines() else: stopwords = download_stopwords() # Strip whitespace around stopwords = [stopword.strip() for stopword in stopwords] # Extend stopwords with own ones, which were determined after first run stopwords = stopwords + STOPWORDS_ADDENDUM try: cloud = WordCloud(stopwords=stopwords).generate(text) cloud.to_file(filename.replace('.html', '.png')) except ValueError: print('Could not generate word cloud for', key) def run_single(path): soup = extract(path) content = transform(soup) load(path, content.strip() if content is not None else '') def run_everything(): with open('urls.txt', 'r') as fh: urls = fh.readlines() urls = [url.strip() for url in urls] paths = download(urls) for path in paths: print('Written to', path) run_single(path) print('Done') if __name__ == "__main__": args = sys.argv if len(args) is 1: run_everything() else: if args[1] == 'download': download([args[2]]) print('Done') if args[1] == 'parse': path = args[2] run_single(path) print('Done')
Что изменилось? Для одного я скачал Список немецких стоп-слов от github. Таким образом, я могу устранить наиболее распространенные слова из загруженного закона текста.
Затем я создал экземпляр WordCloud со списком загруженных записей POTTWORDS и текста закона. Он будет превращен в изображение с тем же базовым именем.
После первого прогона я обнаруживаю, что список стоп-слов является неполным. Поэтому я добавляю дополнительные слова, которые я хочу исключить из полученного изображения.
С этим основная часть веб-соскоба завершена.
Бонус: А как насчет спа?
SPAS – или Onlay Page Приложения – это веб-приложения, в которых весь опыт контролируется JavaScript, который выполняется в браузере. Таким образом, загрузка файла HTML не приносит нам далеко. Что мы должны сделать вместо этого?
Мы будем использовать браузер. С селеном. Обязательно Установите драйвер также. Скачать архив .tar.gz и распаковать его в Bin
Папка вашей виртуальной среды, поэтому она будет найдена селеном. Это каталог, где вы можете найти активировать
Сценарий (на системах GNU/Linux).
В качестве примера я использую Угловой веб-сайт здесь. Angular – это популярное спа-каркас, написанное в JavaScript и гарантированно контролируется им.
Поскольку код будет медленнее, я создаю новый файл под названием Crawler.py
для этого. Контент выглядит так:
from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from wordcloud import WordCloud def extract(url): elem = None driver = webdriver.Firefox() driver.get(url) try: found = WebDriverWait(driver, 10).until( EC.visibility_of( driver.find_element(By.TAG_NAME, "article") ) ) # Make a copy of relevant data, because Selenium will throw if # you try to access the properties after the driver quit elem = { "text": found.text } finally: driver.close() return elem def transform(elem): return elem["text"] def load(text, filepath): cloud = WordCloud().generate(text) cloud.to_file(filepath) if __name__ == "__main__": url = "https://angular.io/" filepath = "angular.png" elem = extract(url) if elem is not None: text = transform(elem) load(text, filepath) else: print("Sorry, could not extract data")
Здесь Python открывает экземпляр Firefox, просматривая веб-сайт и ищет <Статья>
элемент. Это копирование над своим текстом в словарь, который прочитан в трансформировать
Шаг и превратился в WordCloud во время нагрузка
Отказ
При работе с JavaScript-Heake Sites, часто полезно использовать Ждет И, возможно, беги даже execute_script отложить в JavaScript, если это необходимо.
Резюме
Спасибо за чтение этого далеко! Давайте суммируемся тем, что мы узнали сейчас:
- Как соскрести сайт с Python’s
Запросы
упаковка. - Как перевести его в осмысленную структуру, используя
Beautifulsoup
Отказ - Как дальнейшее обрабатывать эту структуру в то, с чем вы можете работать.
- Что делать, если целевая страница опирается на JavaScript.
дальнейшее чтение
Если вы хотите узнать больше обо мне, вы можете Следуй за мной в Twitter или посетить мой сайт Отказ
Я не первый, который писал о веб-соскобке здесь на FreeCodeCamp. Ясоб Халид и Дейв Грей также сделали это в прошлом: