Как стать автором
Обновить

Комментарии 18

Зачем эта абсолютно бесполезная статья? Иногда очень жаль, что у меня нет возможности минусовать посты.

А чем статья плоха? Серьёзный вопрос. Лично мне она полезна. Наверное, она не очень глубокая (мне трудно оценить), но тут достаточно удобная подборка основ в одном месте, самое то, чтобы быстро въехать в тему, а дальше уже углубляться в то, что непосредственно нужно. По крайней мере, так кажется на мой непросвещённый взгляд, я не Python-разработчик, и веб-скрейперы писал только на уровне Hello World :)

Дело в том, что статья именно на уровне Hello World, не более того. Больше похоже на рекламу курсов python, потому что все остальные языки ацтой и сложна

В своё время отбирал материалы на Medium, где 90% статей как раз уровня HW (и очень, ну очень много именно про это), и могу сказать, что про пространства имён или обработку ошибочной разметки мало где даже вспоминают. Так что именно эта статья выбивается из ряда "HW в скрейпинге".

Думаю, основная проблема статьи в ее непрактичности("лабораторности"). По сути, все инструменты имеют место быть, но на деле столкнулся с тем, что потратил время, а есть решения лучше или искал не там. Заранее извиняюсь, что умничаю и развожу воды, сам не спец, но вдруг что-то из этого поможет и сэкономит время/нервы:))) Делюсь своими "граблями" и почти все, что ниже можно найти в статье how to Bypass Cloudflare от zenrows или конкурентов(там одно и то же+-).
К сути:
1) requests - основа, поиграть с ней стоит но читал, что он не thread safe(для многопоточной работы), про асинхронность не скажу, кажется, все норм. И не помню, но что-то не так у него было с http/2. Но главное - те же httpx, aiohttp в разы быстрее(вроде на страничке github aiohttp есть замеры), на выходе - потерял время ковыряя не тот модуль, надо было или с 1го из этих 2х модулей сразу стартовать или учить scrapy.
2) Асинхронность(asyncio) - В статье ни слова(scrapy не в счет:)))), хоть в таких задачах она сама напрашивается. Да и в любом случае знать это стоит.
3) Кэш, кажется ботов индексации - почему-то очень редко в статьях про парсинг/скрепинг не пишут - webcache.googleusercontent(если он есть, то можно дернуть данные крайне быстро и легко). если вам повезет, выиграете тонну времени, но данные могут быть несвежими.
4) Api - пока знакомился со скрейпингом, часто видел фразу как в статье мол смотрите апи. Для полного новичка это было как "потрать месяц в поиске не там:)))". Про бесплатный открытый апи с документацией думаю можно только мечтать, обычно начинают с devtools(f12-сеть-fetch/xhr и ловить json с данными, а дальше тестить запросы на эти адреса. кстати, нажав по запросу правой кнопкой можно скопировать, например как fetch, так его проще читать), но думаю стоит упомянуть тот же wireshark(к сожалению, еще не дорос, только собираюсь знакомиться:)))). К слову, в статье большой кусок посвящен отлову в разметке, но сейчас куча сайтов на SSR фреймворках типа next/nuxt, которые кидают сразу статику и у них частенько все интересное скриптом валится в window.__NEXT_DATA__ и тп, другими словами, нужно просто поковыряться в скриптах исходного кода страницы и поискать те же id(уникальные элементы или большие блоки) на странице или в общем поиске девтулзов и вместо плясок вокруг тегов можно дернуть один скрипт и распарсить строку в json.
5) Обнаружение - в статье от zenrows есть список, что нужно и как найти свои следы, я бы только добавил сайт детектор https://abrahamjuliot.github.io/creepjs/, там куча всего, но иногда такие сайты прямо выручают, особенно при играх с прокси.
6) 2 маленьких момента про селениум(вроде в пюппитере тоже есть) - можно в опциях указать правила загрузки страницы(pageLoadStrategy), то есть когда браузер считает страницу загруженной, это может экономить время или давать возможность подхватывать данные до редиректа из скрипта(только аккуратно, поиски элементов скорее отвалятся) и второе - есть возможность подключить девтулзы(тащить оттуда json если апи никак не пускает и застряли, лично меня это пару раз спасало)
ПС: у beautifulsoup есть оф документация на русском https://www.crummy.com/software/BeautifulSoup/bs4/doc.ru/bs4ru.html

У меня опыт по скрапингу уровня hello world. Подскажите, может сталкивались с такой ошибкой. Использовал selenium. При запуске кода на локальном компьютере все работает. Когда пытался перенести проект на сервер(сперва с помощью docker потом прямой установкой вручную) на Ubuntu, ничего не запускается так как webdraiver отказывается работать с chrome. Возможно что-то с версиями chrome на Ubuntu. Но я их массу перепробовал ничего не запускается. Пробовал даже chromium. Возможно подскажите направление куда копать.?

Самое простое а этой ситуации сделать контейнер с нужным селениумом и подключаться к нему. А так - в селениуме есть таблица совместимости с версиям браузера и версией драйвера. Поищите.

А сам браузер(драйвер) установлен? Посмотрите на модуль, он автоматически ставит и обновляет хром драйвер(вроде есть и мозилла) https://pypi.org/project/webdriver-manager

Как альтернатива, можно поставить вручную(если не ошибаюсь, с недавних пор хром драйвер не нужно ставить вручную, но на всякий случай инструкция https://losst.pro/ustanovka-selenium-v-linux) учтите, что браузер и драйвер должны быть совместимы.

Или взять готовые модули, например undetected-chromedriver или selenium-wire. Там, насколько помню все в пакете.

Не знаю на сколько будет полезный мой ответ. Я использую docker-compose. Selenium использую через хаб, а браузеры в отдельных нодах селениума. Вот конфиг docker-compose. Но нужно учесть что в нем убран сам проект, и по этой причине нет проброски портов.

docker-compose.yml
version: '3.6'
services:
  firefox:
    image: selenium/node-firefox:dev
    shm_size: 2gb
    deploy:
      resources:
        limits:
          cpus: '0.5'
          memory: 1G
    depends_on:
      - selenium
    environment:
      - SE_EVENT_BUS_HOST=selenium
      - SE_EVENT_BUS_PUBLISH_PORT=4442
      - SE_EVENT_BUS_SUBSCRIBE_PORT=4443
      - SE_OPTS=--http-logs true
  chrome:
    image: selenium/node-chrome:dev
    shm_size: 2gb
    deploy:
      resources:
        limits:
          cpus: '0.5'
          memory: 1G
    depends_on:
      - selenium
    environment:
      - SE_EVENT_BUS_HOST=selenium
      - SE_EVENT_BUS_PUBLISH_PORT=4442
      - SE_EVENT_BUS_SUBSCRIBE_PORT=4443
      - SE_OPTS=--http-logs true
  selenium:
    image: selenium/hub:latest
    restart: always
    environment:
      - SE_NODE_SESSION_TIMEOUT=30
      - SE_SESSION_REQUEST_TIMEOUT=30
      - SE_NODE_MAX_SESSIONS=3
      - SE_NODE_OVERRIDE_MAX_SESSIONS=true
    healthcheck:
      test: ["CMD", "/opt/bin/check-grid.sh", "--host", "0.0.0.0", "--port", "4444"]
      interval: 15s
      timeout: 30s
      retries: 2

Вот код использования на PHP, я его подредактировал и сильно сократил. Но думаю реализацию на других языках будет похожей. Код выдран из контекста и из рабочей реализации.

PHP
use Facebook\WebDriver\Remote\DesiredCapabilities;
use Facebook\WebDriver\Remote\RemoteWebDriver;
use Facebook\WebDriver\Remote\WebDriverCapabilityType;
...

// выбираем рандомный браузер
$capability = (mt_rand(1, 100)) < 51 ? DesiredCapabilities::firefox() : DesiredCapabilities::chrome();
// тут у меня постановка рандомного прокси
$capability->setCapability(WebDriverCapabilityType::PROXY, $this->generateProxyOptions($proxy));

// коннект к хабу селениума, в конце настройки таймаутов
try {
    $driver = RemoteWebDriver::create(env('SELENIUM_SERVER_URL', 'http://localhost:4444/wd/hub'), $capability, 15 * 1000, 120 * 1000);
} catch (Exception) {
    continue;
}

// получаем содержимое страницы
try {
    $driver->manage()->timeouts()->pageLoadTimeout(120);
    $driver->get($address);

    $content = $driver->getPageSource();
} catch (Exception $exception) {
    // тут у меня много кода, который тут не нужен
}

// закрываем браузер
try {
    $driver->quit();
} catch (Exception) {

}

Спасибо. Попробую разобраться.

Статья очень полезная, в интернете не мог сходу найти полезное по данной теме. Ваш комментарий видимо был написан для повышения собственной доминантности в глазах стаи.

В целом годно, но слишком много названия библиотек и мало конкретики по каждой.


Довольно странно, что даются советы по добавлению опций с изменением размеров окна в селениум, но при этом не оговаривается про его детект


opts.add_argument('--disable-blink-features=AutomationControlled')
# спрятать selenium от обнаружения сайтом

Да и можно было бы описать логику через классы.

возможно выглядело бы лучше так:

names.append(name)

groups.append(group)

local_names.append(local_name)

photographs.append(photograph)

if not photograph:

continue

response = request.get(photograph)

if response.status_code != 200:

continue

Еще бы знать, что такое скрейпинг. Что-то со скрепками связанное, наверное.

Со скрепами, а не скрепками. Нельзя уменьшительно ласкать скрепы.

Для "табличных" данных (в которых придется преодолевать "красивости" верстки чтобы получить настоящие числа на выходе) - хорошей практикой до запуска тяжелых scraping-либ стал обычный Pandas:
import pandas as pd
for tab in pd.read_html('https://...'):
tab

При запуске в локальном JupyterLab или JupyterLight (браузер) вы получите все "таблички" c web-страницы, неважно каким кодом они формируются. Таблицы будут состоять из 5+5 строк (первые, последние). Допечатав tab.info() можно оценить масштабы трагедии (качество данных) и можно сразу приступить к поискам другого, более консистентного сайта. Благо почти всегда выбор есть.

к сожалению этот механизм плохо работает на реальный сайтах, которые не заботились о том, чтобы такие инструменты их распознали

я написал и запустил в работу инструмент для сбора сообщений с сайта yaplakal для создания датасета для машинного обучения. там нужно активно парсить таблицы (все сообщения в таблицах). На этом ресурсе надо искать поля целенаправленно, чтобы найти нужные данные. Pandas много мусора собирает

Зарегистрируйтесь на Хабре, чтобы оставить комментарий