Форум программистов, компьютерный форум, киберфорум
Python: Web
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.79/34: Рейтинг темы: голосов - 34, средняя оценка - 4.79
4 / 4 / 2
Регистрация: 04.04.2015
Сообщений: 186

Beautiful Soup 4, сравнение html-парсеров при запуске в потоке

04.04.2018, 21:03. Показов 7734. Ответов 47
Метки нет (Все метки)

Студворк — интернет-сервис помощи студентам
Здравствуйте, спарсил страницу с помощью lxml, встроенного в Beautiful Soup - выдал 30 секунд. Не поверил, начал искать ошибки и оптимизировать. Ничего конкретного не получилось, время парсинга примерна такая же. Вспомнил, что у Beautiful Soup есть еще 2 других парсера html.parser и html5lib, в итоге их результаты:
Запуск в отдельном потоке Запуск в общей программе, без создания отдельного потока
html.parser:2 1.44
html5lib: 14 5.5
lxml: 30 1.24

И собственно вопрос, почему в потоке lxml так теряет в скорости? Хотя он считается самым быстрым
Метод запуска потока:
Python
1
2
3
4
5
6
def starting_threading():
    while q.empty()==False:
        if(threading.active_count()<=threads_count):
            t = threading.Thread(target=all_parsing, args=(q,))
            t.start()
            print("Старт потока",t)
q-очередь, threads_count=1.
Вдруг кому-то захочется спарсить эту же страницу ради спортивного интереса: https://www.mvideo.ru/smartfon... rtfony-205 . Парсить только ссылки на телефоны 1 страницы (этой). Пишите библиотеку и язык программирования для сравнения. Должен быть запрос страницы, без сохранения ее на диск, а потом ее парсинга
0
IT_Exp
Эксперт
34794 / 4073 / 2104
Регистрация: 17.06.2006
Сообщений: 32,602
Блог
04.04.2018, 21:03
Ответы с готовыми решениями:

Beautiful Soup Python
Я пишу программу открывающую все ссылки на указанной странице и выписывает те, у которых в url есть id= и т.д. Но по какой-то причине в...

Парсинг на Python с Beautiful Soup
Напишите 2 парсера. Первый парсер разработайте для скрапинга сайта pleer.ru, где необходимо вытащить текст из колонки категорий(см. скрин...

Beautiful Soup поиск по атрибуту
Добрый вечер. Подскажите пожалуйста как с помощь bs4 получить все li c data-xxxx, xxxx-каждый раз новое

47
║XLR8║
 Аватар для outoftime
1212 / 909 / 270
Регистрация: 25.07.2009
Сообщений: 4,361
Записей в блоге: 5
13.04.2018, 15:48
Студворк — интернет-сервис помощи студентам
Цитата Сообщение от danilshik Посмотреть сообщение
А возможно ли сохранить результат запроса? Идея такая: сначала получаем результаты запросов, а потом потоками обрабатываем эти страницы? По идее же быстрее должно быть
Быстрее не будет. Не с потоками, не на CPython.

Цитата Сообщение от danilshik Посмотреть сообщение
Уже тестировали, ThreedPool большую выгоду дает
Заблуждаетесь. Вы начинаете асинхронно выкачивать данные, тем самым уменьшая задержки на сетевые операции. Если бы вы делали то что пишете, а именно выкачивали данные синхронно, дабы избежать блокировок и прочего. Время выполнения было бы даже большим чем если бы вы всё делали в одном потоке из-за накладных расходов на управление потоками.

Разберистесь в чем разница между процессом и потоком, и что такое GIL в CPython,
0
4 / 4 / 2
Регистрация: 04.04.2015
Сообщений: 186
13.04.2018, 16:17  [ТС]
Цитата Сообщение от outoftime Посмотреть сообщение
Заблуждаетесь. Вы начинаете асинхронно выкачивать данные, тем самым уменьшая задержки на сетевые операции.
Не совсем понял. Вы хотите отправлять запросы async и все это в пуле?

Добавлено через 2 минуты
Цитата Сообщение от outoftime Посмотреть сообщение
Сообщение от danilshik
Уже тестировали, ThreedPool большую выгоду дает
Про это имелось ввиду: мы отправляем запрос c помощью request, получаем ответ, парсим. Все это в нескольких потоках, процессах. Так вот из всех, ThreedPool на несколько секунд быстрее

Добавлено через 1 минуту
Вот этот код
Код

Python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
1
 
from concurrent.futures import ThreadPoolExecutor, as_completed
import time
import requests
#from multiprocessing.dummy import Pool as ThreadPool
from multiprocessing import Pool
import logging
from bs4 import BeautifulSoup
import threading
import queue
import lxml.html
log = logging.getLogger(__name__)
count_thread=10
q_list =[]
q_url=queue.Queue()
cities=[]
url_main="https://www.mvideo.ru"
 
 
def parse_list_object(q_list):
    start = time.time()
    url=q_list[0]
    city=q_list[1]
    log.info("Парсинг list: %s | %s",url,city)
    r=requests.get(url)
    html=get_html(r)
    for elem in html.xpath(".//div[@class='c-product-tile sel-product-tile-main ']"):
        error_div=elem.xpath(".//span[@class='c-product-label__text']")
        if(error_div!=[]):
            error_div=error_div[0]
            error_text=error_div.xpath("span[2]/text()")[0]
            if(error_text!="Витринный образец"):
                continue
        link_object=url_main+elem.xpath(".//h4[@class='e-h4 u-pb-0']/a")[0].get("href")+"/shopdirections?cityId="+city
        q_url.put(link_object)
        log.info(link_object)
    end = time.time()
    log.info("Спарсен за %s", end-start)
def parse_object(url):
    r=requests.get(url)
    log.info("Запрос")
    html=get_html(r)
    log.info("Парсинг")
    print("Парсинг")
def start_threads():
    # with ThreadPoolExecutor(count_thread) as executor:
    #     for _ in executor.map(parse_list_object, q_list):
    #         pass
 
    with Pool(count_thread) as p:
        p.map(parse_list_object, q_list)
 
    # pool = ThreadPool(count_thread)
    # results = pool.map(parse_list_object, q_list)
    # pool.close()
    # pool.join()
 
 
def get_html(request):
    return lxml.html.fromstring(request.text)
def parse_city():
    r = requests.get("https://www.mvideo.ru/sitebuilder/blocks/regionSelection.json.jsp?pageId=homepage&pageUrl=/&").json()
    log.info('Запрос страницы городов')
    html = lxml.html.fromstring(r["htmlContent"])
    log.info('Получение html')
    for elem in html.xpath("//input[@name='/com/mvideo/domain/RegionSelectionFormHandler.cityId']"):
        city=elem.get("value")
        cities.append(city)
        log.info(city)
 
def all_parsing():
    for city in cities:
        r = requests.get("https://www.mvideo.ru/smartfony-i-svyaz/smartfony-205/f/page=" + str(1)+"?cityId="+str(city))
        log.info("Переход на 1 страницу города:"+city)
        html =get_html(r)
        count_list=html.xpath("//a[@class='c-pagination__num c-btn c-btn_white ']/text()")[0]
        log.info("Парсинг")
        log.info(count_list)
        for i in range(1,int(count_list)+1):
            parameters=[]
            parameters.append("https://www.mvideo.ru/smartfony-i-svyaz/smartfony-205/f/page=" + str(i)+"?cityId="+city)
            parameters.append(city)
            q_list.append(parameters)


Добавлено через 1 минуту
Если посмотрите на код, то увидите закоментированные строчки в коде, на разные способы создания потоков/процессов
0
║XLR8║
 Аватар для outoftime
1212 / 909 / 270
Регистрация: 25.07.2009
Сообщений: 4,361
Записей в блоге: 5
13.04.2018, 16:56
Цитата Сообщение от danilshik Посмотреть сообщение
Не совсем понял. Вы хотите отправлять запросы async и все это в пуле?
Цитата Сообщение от danilshik Посмотреть сообщение
Все это в нескольких потоках, процессах.
Цитата Сообщение от outoftime Посмотреть сообщение
Вы начинаете асинхронно выкачивать данные
Вникай

Цитата Сообщение от danilshik Посмотреть сообщение
Если посмотрите на код
Не хочу я на него смотреть, код ужасный, форматирования нет, PEP8 писали специально для Вас.
0
Эксперт Python
5439 / 3860 / 1215
Регистрация: 28.10.2013
Сообщений: 9,552
Записей в блоге: 1
13.04.2018, 17:44
Цитата Сообщение от danilshik Посмотреть сообщение
почему то request+threedpoolexecutor в 10 потоков выполняется в 2 раза быстрее чем async с семафором 10
Потому что два ваших кода не сопоставимы между собой по логике. (Про необходимость следования PEP8 тоже не лишнее было указание).
Просто подсчитайте какое число корутин у вас запускается в асинхронном коде. Оно куда больше 10. Поэтому семафор с ограничением на 10 дает бОльшую задержку. Есть выставить в семафор любое большое число (безлимит) - асинхронный код должен стать быстрее многопоточного.
0
4 / 4 / 2
Регистрация: 04.04.2015
Сообщений: 186
13.04.2018, 18:13  [ТС]
Цитата Сообщение от Garry Galler Посмотреть сообщение
Просто подсчитайте какое число корутин у вас запускается в асинхронном коде. Оно куда больше 10. Поэтому семафор с ограничением на 10 дает бОльшую задержку. Есть выставить в семафор любое большое число (безлимит) - асинхронный код должен стать быстрее многопоточного.
Тут возникает 2 проблемы, если указать большое число
1. ошибка raise asyncio.TimeoutError from None concurrent.futures._base.TimeoutError, как я понял, это ошибка timeout запросов.
2. максимальное количество запросов, которые мы можем отправить серверу, чтобы не получить бан.
И в вопросе имелось ввиду некоторого ограничения, которые постоянно будет действовать, в данном случае макс. количество запросов.
0
Эксперт Python
5439 / 3860 / 1215
Регистрация: 28.10.2013
Сообщений: 9,552
Записей в блоге: 1
13.04.2018, 19:37
За asyncio.TimeoutError сказать ничего не могу - она возникает у меня только если я сам задам timeout (например 1\10 или 1\100 секунды для запроса страницы). По дефолту там не помню сколько, но достаточно много.
А по семафору, как я уже писал, вы неверно приравниваете выполнение 10 потоков (и фиг знает сколько заданий внутри них) и 10 корутин. Это не одно и тоже.

P.S. Советую полностью отрефакторить код - он реально трудночитаемый и вчитываться в него мало кому интересно.
Все url, селекторы и прочие строки не харкодятся в функциях, а определяются в переменных. В функциях нужно использовать переменные вместо строк. Пробелы. Код без пробелов - это ужас.
0
║XLR8║
 Аватар для outoftime
1212 / 909 / 270
Регистрация: 25.07.2009
Сообщений: 4,361
Записей в блоге: 5
14.04.2018, 16:09
Garry Galler, ТС-у надо весь курс вычитать с нуля, чтобы он понял в чем проблема с его "замерами". Вам надо либо самому вычитать его либо послать RTFM.
0
4 / 4 / 2
Регистрация: 04.04.2015
Сообщений: 186
19.04.2018, 19:39  [ТС]
Вообщем для себя я сделал такие выводы: в случае если есть какое то ограничение, например некоторое максимальное количество запросов для сервера, все же лучше использовать concurrent.futures+request. В случае если ограничение не маленькое, либо его вовсе нет, то лучше asyncio
0
Надоела реклама? Зарегистрируйтесь и она исчезнет полностью.
BasicMan
Эксперт
29316 / 5623 / 2384
Регистрация: 17.02.2009
Сообщений: 30,364
Блог
19.04.2018, 19:39

В чем проблема? (Beautiful Soup)
from bs4 import BeautifulSoup import requests headers = { 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)...

Парсинг Beautiful Soup 4 и Selenium.Webdriver
Здравствуйте, пишу парсер под сайт https://www.kimovil.com/ru/ и возникает проблема: товары динамически подгружаются. Сначала были...

Beautiful Soup - существует ли ограничения на длину получаемых данных?
Здравствуйте! Почему при парсинге html достается только часть данных, которые все лежат в одном теге. данные - это 1 000 000 цифр. Получаю...

Извлечь атрибуты a href и img src одновременно, используя Beautiful Soup
Знаю как извлечь и показать a href urls = soup.findAll('a') for url in urls: print(url) Но как можно найти...

Как убрать soup = BeautifulSoup (html) из кода?
Приветствую всех, только недавно начал изучать Python, дали задание: сделать парс расписания нашей группы в универе. Пользовался Beautiful...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
48
Ответ Создать тему
Новые блоги и статьи
Про "Windows must die!"
kumehtar 04.11.2026
Знаете, чет накатило. . . . Когда-то это было почти боевым кличем: мол, нормальный человек сидит на DOS, OS/ 2 или Linux, а вот это вот - Must Die. А теперь человек произносит «мастдай» с усмешкой - и. . .
Красочные поля с номером страницы svg+background-image
russiannick 04.11.2026
Красочные поля с номером страницы не менее важны чем в эпоху бумажных книг. Посему спешу представить почтеннейшей публике этот важный инструмент который эти поля и формирует. В процессе разработки. . .
Вступаем в новую фазу генерации favicons, векторную.
russiannick 02.11.2026
Теперь нет нужды скрывать что используется простой svg. Исходный код изображения помещаем в поле и жмем кнопку. Исходник преобразуется в вид корректный для помещения в favicon или в url(). Нажатие. . .
Генератор паролей (вариант №4)
Maks 01.11.2026
После публикации 3-го варианта генератора паролей, разослал его своим коллегам (с целью оценки), в итоге были получены следующие рекомендации: 1. Вернуть возможность использования знаков | 1 l I;. . .
Генератор паролей (вариант №3)
Maks 30.10.2026
Финальная версия генератора паролей 1С. Доработка решения в этот раз коснулась только визуальной части, а именно, добавлен реквизит ДопПараметры (тип Булево), который скрывает/ отображает реквизиты:. . .
Магическое мышление и магия, современная наука не отличима от магии (говорит ИИ Джемени)
zorxor 30.10.2026
Джемени, расскажи, пожалуйста, что такое магическое мышление, что такое магия, почему современная наука чем-то напоминает магию? Фраза «Любая достаточно развитая технология неотличима от магии». . .
За какое время ИИ может подобрать пароль по хешу (рассказывает Джемени ИИ)
zorxor 30.10.2026
Расскажи, Джемени, если известен хэш МД5, например, за сколько ИИ сможет подобрать соответствующий пароль? Искусственный интеллект (ИИ) может подобрать простой или средний по сложности пароль по. . .
Кто убил Suno? Почему наше солнышко погасло? (диалог с ИИ Джемени)
zorxor 30.10.2026
Как убивали Suno. Хронология. «Убийство» музыкальной нейросети Suno — это затяжной процесс, в котором технологический хайп стартапа разбился о жесткую реальность судебных исков от гигантов. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru