Є така некомерційна організація Common Crawl, чиї пошукові роботи обходять сторінки інтернету з метою занесення інформації про них до бази даних, доступ до якої є вільним для кожного. І сьогодні я розповім вам, як за допомогою bash написати сценарій оболонки, котрий користуючись Common Crawl API буде завантажувати унікальні внутрішні посилання для списку доменів.
Для початку, трохи розберемось як працює Common Crawl API. На сторінці https://index.commoncrawl.org/ є щомісячний список індексів, де цікава для нас колонка таблиці це “API endpoint”:
Тобто, якщо ми бажаємо витягти дані з індексу за вересень 2020 року, нам потрібен запит до API за ось таким посиланням - https://index.commoncrawl.org/CC-MAIN-2020-40-index
, але запит також має ще містити додаткові параметри, що б API знав що саме нас цікавить та в якому форматі, тож ми будемо використовувати наступні параметри - ?url=*.exception.net.ua&output=json
. Перевіримо запит, аби бути впевненими, що все працює:
$ curl -s "https://index.commoncrawl.org/CC-MAIN-2020-40-index?url=*.exception.net.ua&output=json" | jq -r .url | uniq
https://exception.net.ua/post/
https://exception.net.ua/post/bash-history-search-up-down-keys/
https://exception.net.ua/post/bash-split-one-file-into-multiple-files-based-on-filter/
https://exception.net.ua/post/block-network-access-of-a-process/
...
І відразу маленьке пояснення. Ми вказали параметр url=*.exception.net.ua
з ‘*.’ на початку домену, бо наc цікавлять внутрішні посилання не тільки цього домену, але і його піддоменів. Параметр output=json
повідомляє Common Crawl API, що нам потрібна відповідь від сервера у форматі JSON.
Отже, тепер, коли ми навчились працювати з Common Crawl API, перед нами постає нова задача - отримати посилання для списку доменів та записати їх в один файл. При цьому посилання з одного домену повинні йти один за одним. Ми могли б скористатись для цього звичайним циклом, але це буде повільно, а посилання нам потрібні якомога швидше.
Звісно, ми будемо використовувати xargs, аби завантажувати посилання для кожного домену в окремому процесі. Це, звісно, що прискорить наш сценарій оболонки. Але тут з’являється одна проблема - як нам записувати посилання у файл у відповідному порядку? Я вирішив розв’язати цю проблему наступним чином:
xargs
створює процеси і кожен з них отримує один домен з файлуdomains.txt
.- Використовуючи
curl
таjq
процес завантажує внутрішні посилання у тимчасовий файл/tmp/$domain.list
. - Далі процес блокує доступ до файлу
result.list
іншим процесам за допомогоюflock
та дописує до нього дані з тимчасового файлу. - Після запису даних в
result.txt
, процес видаляє тимчасовий файл та завершує роботу. xargs
стартує новий процес поки не закінчаться домени з файлуdomains.txt
.
Звучить складно, проте наш сценарій буде займати лише один рядок:
cat domains.txt | xargs -I{} -n1 -P0 sh -c 'curl -s "https://index.commoncrawl.org/CC-MAIN-2020-40-index?url=*.{}&output=json" | jq .url | uniq > /tmp/{}.list; { flock -x 3; cat /tmp/{}.list >&3; } 3>> result.list; unlink /tmp/{}.list'
Так, це все… Сподіваюсь, що цей приклад допоможе вам у розв’язуванні схожих задач.