Вишкрібання у Web за допомогою Go
Переклад статті. Посилання на оригінал.
https://medium.com/@shahidahmed.org/programming-in-go-for-web-scraping-aedf937e769d
Код виглядає просто. Розробка швидка. І при цьому Go є потужною мовою програмування загального призначення. Ви можете використовувати GO для розробки будь-якої програми. Незалежно від того, чи це програма на рівні ОС, чи служба масштабу Google, Go може стати вашим найкращим вибором як мовою розробки. У цій статті ми напишемо програму веб-збирання та покажемо, як можна швидко створити корисну та ефективну програму. Наша мета — написати програму, яка просто працює. Можливо, у нього не так багато наворотів. Добре. Спочатку ми напишемо базову програму, а потім створимо її, застосовуючи нові методи та найкращі практики. Багато новачків і ентузіастів Go знаходять цей підхід цікавим.
Наше завдання полягає в тому, щоб зібрати деяку інформацію про фільми Disney, випущені на даний момент. Якщо ми шукаємо в Google «повний список фільмів Disney», ми отримуємо багато посилань. Одна з них з IMDB — популярного веб-ресурсу фільмів. Давайте клацнемо URL: Link. З’явиться сторінка під назвою «Повний список фільмів Уолта Діснея». Зрозуміло, що ми в правильному місці.
Сторінка виглядає забрудненою всілякою рекламою, кнопками, посиланнями та зображеннями. Але ми також бачимо інформацію про фільми в напів табличному форматі. Це наша мета. Ми очистимо цю частину сторінки, витягнемо необхідні фрагменти інформації та збережемо їх у текстовому файлі на нашому комп’ютері. От коротко про те шо ми хочемо зробити.
Спочатку нам потрібно поглянути на внутрішню структуру сторінки. У Chrome або Microsoft Edge є простий спосіб зробити це. Зберігаючи сторінку в браузері, запустіть Інструменти розробника (у розділі «Додаткові інструменти» в головному меню), і ви побачите повний DOM сторінки. У Firefox запустіть Web Developer, а потім Inspector. Ви побачите сторінку.
Не так просто пройти це дерево DOM і знайти конкретні слова. Отже, давайте скористаємося пошуком, набравши <ctrl-F> і знайшовши назву першого фільму — «Білосніжка». Так, тепер ми бачимо «Білосніжку та семеро гномів», прихованих під кількома ієрархічними рівнями <div..>, <span..>, <p..> та інших елементів. Завдання полягає в тому, як програмно розмістити їх у середині такої складної структури. На щастя, Go має багатий набір бібліотек з відкритим вихідним кодом для роботи майже з усім, що тільки можна придумати — мережею, базою даних, мультимедіа, Інтернетом речей, машинним навчанням тощо. Також є деякі бібліотеки для веб-збирання. Найпопулярніший, мабуть, Коллі. Ми будемо використовувати його для наших потреб.
Перш ніж почати кодування, давайте визначимо основні кроки, які нам потрібно реалізувати:
Визначити вхідні дані (веб-сторінка для сканування) і вихід (текстовий файл для запису зібраної інформації)
Створити і відкрити текстовий файл
Записати заголовки стовпців
Ініціалізувати процедуру очищення
Витягнути необхідну інформацію про кожен фільм
Записати в текстовий файл
Закрити текстовий файл
Давайте зараз напишемо програму.
Перший розділ схожий на шаблонний код із інформацією про імпорт пакета. Бібліотеки Colly імпортуеться рядком «github.com/gocolly/colly», «os» для створення/маніпулювання текстовим файлом і «encoding/csv» для вихідного тексту у форматі CSV. Усі ці бібліотеки є частиною стандартного набору Golang, за винятком Colly, яка є бібліотекою третьої сторони. Давайте встановимо Colly у вашому середовищі розробки, виконавши це:
go get github.com/gocolly/colly
Далі ми визначаємо вхідні дані (URL-адресу сторінки, яку потрібно отримати), створюємо вихідний текстовий файл і записуємо в текстовий файл заголовки стовпців, як-от серійний номер, назва фільму, рік випуску тощо. Потім настає найцікавіша частина коду — сканування за допомогою Colly.
В основі Colly лежить об’єкт Collector. Він обробляє дві речі — 1) мережевий зв’язок і 2) виконання приєднаних зворотних викликів під час виконання завдання збирача. Щоб працювати з Colly, нам потрібно спочатку створити екземпляр об’єкта Collector. А поки давайте створимо об’єкт за замовчуванням без налаштування.
c := colly.NewCollector()
Тепер нам потрібно приєднати різні функції зворотного виклику до об’єкта Collector, щоб обробляти різноманітні події, пов’язані з мережевим запитом (request) і відповіддю (response). Ось кілька важливих зворотних викликів, які можна використовувати (вони викликаються в зазначеному порядку):
OnRequest() — викликається безпосередньо перед тим, як зробити запит
OnError() — викликається, якщо під час запиту виникає будь-яка помилка
OnResponse() — викликається одразу після отримання відповіді
OnHTML() — викликається, коли Colly виявляє певний текст у відповіді HTML
Найважливішим зворотним викликом для наших потреб є OnHTML(). Ось код:
c.OnHTML(`.lister-item-content`, func(e *colly.HTMLElement) { ….. }
Він інструктує Colly, що слід виконувати наступні операції, коли знаходить елемент <div> із class=”lister-item-content”. "." (крапка) перед «lister-item-content» вказує, що це для атрибута «class», наприклад, <div class="lister-item-content" …>. Замість класу деякі елементи <div> можуть використовувати такий «id»: <div id=”content-extra-header” …>. У цьому випадку ми б використали «#» замість «.».
Таким чином, якщо Colly знаходить елемент <div class=”lister-item-content” …> будь-де в HTML-документі, він починає звідти і виконує інструкції, вказані в блоці коду. Деякі з цих інструкцій і відповідних операцій:
number := e.ChildText(“.lister-item-index”)
Витягнути значення елемента <span class=”lister-item-index” …>
name := e.ChildText(“.lister-item-index ~ a”)
Витягнути значення елемента <a href=”…”> який є братом елемента <span class=”lister-item-index” …>.
rating := e.ChildText(“[class=’ipl-rating-star small’] .ipl-rating-star__rating”)
Витягнути значення елемента <span class=”ipl-rating-star__rating”> який є нащадком елемента <div class=”ipl-rating-star small” …>.
vote := e.ChildAttr(“span[name=nv]”, “data-value”)
Витягнути значення “data-value” атрибута, де елемент виглядає <span name=”nv” data-value=”xxx”>.
gross := e.ChildText(“.text-muted:contains(‘Gross’) ~ span[name=nv]”)
Витягнути значення елемента <span name=”nv”> який є братом елемента <div class=”text-muted” …> значення якого містить слово “Gross”.
Ми також можемо витягнути валову суму за допомогою такого селектора:
gross = e.ChildText(“[class=’text-muted text-small’] span:contains(‘$’)”)
Витягнути значення елемента <span ..> якщо його значення містить рядок «$» і воно є нащадком <p class=’text-muted text-small”>.
Пам’ятайте, що для обходу дерева DOM Colly використовує GoQuery, яка є реалізацією Go jQuery — широко використовуваної бібліотеки Java для роботи з DOM. Це означає, що якщо у вас є складний селектор, який працює в jQuery, він також повинен працювати в Colly.
Повернемося до нашого коду. У зворотному виклику OnHTML() ми спочатку витягуємо всю необхідну інформацію. Потім ми записуємо їх у текстовий файл. Отже, зворотній дзвінок готовий.
c.Visit(fetchURL)
Це завершальний рядок. Тут ми повідомляємо об’єкту Collector відвідати сторінку, вказану fetchURL. Тепер збирач зробить мережевий запит і отримає відповідний HTML-документ. Під час цього процесу щоразу, коли він бачить такі події, як OnHTML(), він викличе відповідні зворотні виклики, які збиратимуть пов’язані фрагменти інформації та записуватимуть їх у вихідний файл. Це воно. Зішкріб майже завершено.
Майже, але ще не повністю. У нас є два пункти, що очікують на розгляд. Один — скинути об’єкт запису, щоб гарантувати, що весь текст у буфері буде записаний у файл, а інший — закрити текстовий файл. Ми вже подбали про них за допомогою цих двох операторів defer:
defer file.Close()
defer writer.Flush()
Ми знаємо, що всі виклики defer надходять у стек. Коли функція виклику завершена, відкладені виклики defer виконуються в порядку «останній прийшов-перший вийшов» (LIFO). Таким чином, у нашій програмі спочатку буде змитий (flushed) автор. Потім вихідний файл буде закрито. І програма закінчилася.
Ось друга частина нашої повної програми. Щоб отримати повний вихідний код із Github, використовуйте цю URL-адресу:https://github.com/shahidcc/Go-for-web-scraping
Ми припускаємо, що ви вже налаштували середовище розробки Go на своєму комп’ютері. Отже, ви можете запустити цю програму, перейшовши до терміналу та ввівши команду:
go run scrape-1.go
Якщо ви хочете створити виконувану програму, введіть команду:
go install scrape-1.go
Він створить один виконуваний файл під назвою «scrape-1.exe» у папці bin (Windows). Ви можете будь-коли поділитися файлом з іншими для запуску на їхніх комп’ютерах.
Таким чином, ми написали швидку та брудну програму, яка очищає необхідну інформацію з веб-сторінки та скидає її в текстовий файл у форматі CSV. У наступній статті ми розглянемо два складних випадки використання. Одним із них було б перейти за посиланнями, наведеними на сторінці, і зайти вглиб інших підсторінок. Інший — запустити багато процедур скрапінгу одночасно, щоб ми могли збирати інформацію з кількох сайтів паралельно та збирати її в один вихідний файл. А поки насолоджуйтесь програмуванням у Go. Це дуже весело *