Страницы

Поиск по вопросам

Показаны сообщения с ярлыком beautiful-soup. Показать все сообщения
Показаны сообщения с ярлыком beautiful-soup. Показать все сообщения

суббота, 11 апреля 2020 г.

Адресация по объектам BeautifulSoup

#python #beautiful_soup

                    
Пищу парсер на Python 2.7, используя BeautifulSoup 4. Возникла трудность.

Извлек я все элементы  со страницы.

for p in allPosts:
    postIMG = p.find_all('img')


В итоге получилось:

Название
Название 2



Как обратится к тексту? Можно как-то через точку? postIMG.alt ? Или как лучше?
Как красивее всего извлечь урл картинки?

    


Ответы

Ответ 1



find_all возвращает список объектов класса bs4.element.Tag и к аттрибутам элемента можно обратиться через словарь attrs: for p in allPosts: postIMG = p.find_all('img') print postIMG[0].attrs['alt'] print postIMG[0].attrs['src'] Если картинка в посте одна, то удобнее использовать метод find, вместо find_all: for p in allPosts: postIMG = p.find('img') print postIMG.attrs['alt'] print postIMG.attrs['src']

понедельник, 30 марта 2020 г.

BeautifulSoup: построчная обработка таблицы

#python #python_3x #парсер #beautiful_soup #bs4


Помогите пожалуйста разобраться, пытаюсь обработать выгрузку информации о Сisco телефоне
в формате HTML. Необходимые данные лежат в table[2]



    Cisco
Systems, Inc.


Device information

Cisco IP Phone

Device information
Streaming statistics
   Stream 1
...
Service modeEnterprise
Service domain
App load IDrootfs8845_65.12-1-1-12
При попытке вытащить параметры аппарата из таблицы, не отображаются строки param = soup.findChildren("table"[2]) print(param) В выводе получается список без какой либо привязки к строкам, все параметры подряд: .... Service mode, Enterprise, Service domain, , Service state, Idle, .... Однако если сделать поиск по тегу "DIV" param = soup.findChildren("div") print(param) На выводе будет строка необходимых данных, но ее нельзя прогнать через цикл что бы создать словарь, где параметры из одной строки будут ключом - значением (пример "Service mode" : "Enterprise") Подскажите, как правильно обработать таблицу, чтобы создать словарь из параметров в table[2]


Ответы

Ответ 1



Попробуйте так: from bs4 import BeautifulSoup # ... table = root.select_one('table:nth-of-type(3)') # Или так: table = soup.select('table')[2] name_by_value = dict() for tr in table.select('tr'): tds = tr.select('td') name, value = tds[0].text.strip(), tds[2].text.strip() name_by_value[name] = value print(name_by_value) # {'Service mode': 'Enterprise', 'Service domain': '', 'App load ID': 'rootfs8845_65.12-1-1-12'} PS. Заметил, что нужные значения ячеек находятся исключительно в , а значит можно немного конкретизировать поиск: ... for tr in table.select('tr'): tds = [x.text.strip() for x in tr.select('td > b')] name, value = tds[0], tds[1] name_by_value[name] = value ... А если элементов всегда ожидается два, то воспользоваться распаковкой: ... for tr in table.select('tr'): name, value = [x.text.strip() for x in tr.select('td > b')] name_by_value[name] = value ...

понедельник, 24 февраля 2020 г.

Парсинг библиотека BeautifulSoup: как получить элементы <a> с заданным атрибутом

#python #beautiful_soup


Есть ссылки вида:

1
2
3

1
2


Как можно получить href'ы только ссылок с атрибутом "chapter"?
    


Ответы

Ответ 1



from bs4 import BeautifulSoup r = ''' 1 2 3 1 2''' soup = BeautifulSoup(r, 'html.parser') for a in soup.find_all('a', chapter=True): print(a)

Ответ 2



Альтернативный и немного более лаконичный способ - использовать CSS селекторы - на данный момент BeautifulSoup поддерживает ограниченный набор селекторов - но для большинства повседневных задач хватает: for a in soup.select('a[chapter]'): print(a) # или print(a.get_text()) чтобы распечатать тексты ссылок

воскресенье, 16 февраля 2020 г.

Парсинг библиотека BeautifulSoup: как получить элементы <a> с заданным атрибутом

#python #beautiful_soup


Есть ссылки вида:

1
2
3

1
2


Как можно получить href'ы только ссылок с атрибутом "chapter"?
    


Ответы

Ответ 1



from bs4 import BeautifulSoup r = ''' 1 2 3 1 2''' soup = BeautifulSoup(r, 'html.parser') for a in soup.find_all('a', chapter=True): print(a)

Ответ 2



Альтернативный и немного более лаконичный способ - использовать CSS селекторы - на данный момент BeautifulSoup поддерживает ограниченный набор селекторов - но для большинства повседневных задач хватает: for a in soup.select('a[chapter]'): print(a) # или print(a.get_text()) чтобы распечатать тексты ссылок

пятница, 14 февраля 2020 г.

Парсинг колонки таблицы

#html #python #парсер #beautiful_soup


Не подскажете, как спарсить колонку Bitcoinprice таблицы с сайта MYIP.MS?
Спарсить всю страницу могу, а вот как конкретную колонку таблицы не понимаю.

from bs4 import BeautifulSoup
from urllib.request import Request, urlopen
site= "https://ru.myip.ms/browse/market_bitcoin/%D0%91%D0%B8%D1%82%D0%BA%D0%BE%D0%B8%D0%BD_%D0%B8%D1%81%D1%82%D0%BE%D1%80%D0%B8%D1%8F_%D1%86%D0%B5%D0%BD.html#a"
hdr = {'User-Agent': 'Mozilla/5.0'}
req = Request(site,headers=hdr)
page = urlopen(req)
soup = BeautifulSoup(page, "lxml")
print(soup)


UPD. Разобрался с таблицей, но как можно спарсить остальные страницы таблицы, а не
только 1ую?
    


Ответы

Ответ 1



Это возможно сделать через BeautifulSoup, но гораздо проще будет сделать это через pandas и .read_html() метод, парся таблицу напрямую в DataFrame: import pandas as pd from urllib.request import Request, urlopen site = "https://ru.myip.ms/browse/market_bitcoin/%D0%91%D0%B8%D1%82%D0%BA%D0%BE%D0%B8%D0%BD_%D0%B8%D1%81%D1%82%D0%BE%D1%80%D0%B8%D1%8F_%D1%86%D0%B5%D0%BD.html#a" hdr = {'User-Agent': 'Mozilla/5.0'} req = Request(site, headers=hdr) page = urlopen(req) df = pd.read_html(page.read(), attrs={"id": "market_bitcoin_tbl"})[0] df = df.rename(columns=lambda x: x.strip()) # remove extra newlines from the column names print(df['Bitcoin Price'])

Ответ 2



Что касается Вашей второй проблемы, следовать пагинации мы можем эмулируя XHR POST запросы, попутно сохраняя данные в датафрейм. Что-то вроде вот такого: from time import sleep import pandas as pd import requests host = 'ru.myip.ms' index_url = 'https://ru.myip.ms' home_url = "https://ru.myip.ms/browse/market_bitcoin/%D0%91%D0%B8%D1%82%D0%BA%D0%BE%D0%B8%D0%BD_%D0%B8%D1%81%D1%82%D0%BE%D1%80%D0%B8%D1%8F_%D1%86%D0%B5%D0%BD.html#a" base_ajax_url = "https://ru.myip.ms/ajax_table/market_bitcoin/{page}" with requests.Session() as session: session.headers = { 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3578.98 Safari/537.36', 'Host': host } # visit home page and parse the initial dataframe response = session.get(home_url) df = pd.read_html(response.text, attrs={"id": "market_bitcoin_tbl"})[0] df = df.rename(columns=lambda x: x.strip()) # remove extra newlines from the column names sleep(2) # start paginating with page=2 page = 2 while True: url = base_ajax_url.format(page=page) print("Processing {url}...".format(url=url)) response = session.post(url, data={'getpage': 'yes', 'lang': 'ru'}, headers={ 'X-Requested-With': 'XMLHttpRequest', 'Origin': index_url, 'Referer': home_url }) # add data to the existing dataframe try: new_df = pd.read_html("{0}
".format(response.text))[0] except ValueError: # could not extract data from HTML - last page? break new_df.columns = df.columns df = pd.concat([df, new_df]) page += 1 sleep(1) print(df) В пагинации на этой странице больше 4700 страниц, поэтому я не стал проверять все от начала до конца, но код работает для меня на нескольких страницах. Обратите внимание на следующие вещи: использую requests и requests.Session() для удобного менеджмента веб-скрейпинг сессии подобавлял тут и там искусственные задержки между реквестами, см. How to be a good citizen when crawling web sites? в качестве условия выхода из цикла мы используем факт того, что pandas не может распарсать данные, когда мы достигаем страницы без данных, а только с текстом ошибки - возможно есть получше способ выйти из цикла - например, можно заранее отпарсать кол-во страниц и использовать обычный for цикл

среда, 5 февраля 2020 г.

Получение значения аттрибута “name” тэга “input”

#python #парсер #beautiful_soup


Как получить значение атрибута name всех тэгов input ?

То есть если был тэг




то  в массиве должно быть только значение "value".
Я знаю, что для div'a это можно сделать так:

titles = [div['title'] for div in soup.find_all('div', title = True)]


Но если пробую просто заменить все div на input, а title на name, то сталкиваюсь
с проблемой, что input - зарезервированное слово (возможно, проблема не в этом, но
все равно ничего не работает)
    


Ответы

Ответ 1



Попробуйте: input_names = [tag['name'] for tag in soup.select('input[name]')] Проверка: import requests from bs4 import BeautifulSoup rs = requests.get('https://ru.stackoverflow.com/questions/830858/') root = BeautifulSoup(rs.content, 'html.parser') input_names = [tag['name'] for tag in root.select('input[name]')] print(input_names) # ['q', '_id_', 'qualityBanWarningShown', 'referrer', ...

Ответ 2



если пробую просто заменить все div на input, а title на name, то сталкиваюсь с проблемой, что input - зарезервированное слово Этой проблемы точно нет: >>> import bs4 >>> soup = bs4.BeautifulSoup('', 'html.parser') >>> [input['name'] for input in soup.find_all('input')] ['value'] Хотя input и является встроенным именем, поэтому не рекомендуется его использовать для своих целей, чтобы путаницу не вводить, но локально (как в примере с listcomp) читаемость от использования input не уменьшается. Всегда можно другое имя использовать, если хочется: >>> [tag['name'] for tag in soup.find_all('input')] ['value'] Можно вообще без временных имён обойтись: >>> from operator import itemgetter >>> list(map(itemgetter('name'), soup.find_all('input'))) ['value'] Вы вероятно наткнулись на ошибку с использованием name параметра: >>> soup.find_all('input', name=True) # XXX broken Traceback (most recent call last): File "", line 1, in TypeError: find_all() got multiple values for argument 'name' find_all() got multiple values for argument 'name' ошибка из-за того, что name='input' и name=True передаются в find_all() одновременно. Это легко обойти: >>> soup.find_all('input', dict(name=True)) [] или для читаемости: >>> soup.find_all('input', attrs=dict(name=True)) [] Если вы знакомы с CSS selectors, то можно как @gil9red предложил: >>> soup.select('input[name]') []

четверг, 9 января 2020 г.

Как получить содержимое ссылок?

#python #python_3x #beautiful_soup


Подскажите пожалуйста как получить содержимое ссылок c BeautifulSoup(html, 'lxml')?
Не сами ссылки а название!
есть вот такой код:

html = urllib.request.urlopen('https://kyxni.pro/katalog/')
soup = BeautifulSoup(html, 'html.parser').find('div', class_='builder-posts-wrap')
for i in soup.find_all('h2', class_='post-title'):
print(i)


выводит ссылки:

Кухня ЭЛЕГИЯ

Кухня ДИАНА

Кухня ТЕМЗА

а я хочу получить сами названия: Кухня ЭЛЕГИЯ Кухня ДИАНА Кухня ТЕМЗА и т.д. Подскажите пожалуйста как это реализовать? И как можно открыть сохранённую страницу, что бы каждый раз сайт не грузить? Такая конструкция в коде который выше не работает html = open('kuhni.html').read()


Ответы

Ответ 1



а я хочу получить сами названия: for i in soup.find_all('h2', class_='post-title entry-title'): print(i.text) Когда нужно получить текстовое содержимое, применяйте атрибут text (только не к списку, который возвращается методом find_all). И как можно открыть сохранённую страницу, что бы каждый раз сайт не грузить? Такая конструкция в коде который выше не работает У меня получилось так: html = open('kuhni.html', encoding='utf8').read() P.S. На будущее. Приводите текст ошибок.

Ответ 2



Можно так: In [210]: [x.text for x in soup.select("h2.post-title a")] Out[210]: ['Кухня ЭЛЕГИЯ', 'Кухня ДИАНА', 'Кухня ТЕМЗА', 'Кухня ОРХИДЕЯ', 'Кухня CRYSTAL', 'Кухня SAFARI', 'Кухня SCANDIA', 'Кухня INVERNO', 'Кухня МЕРАНО', 'Кухня МОНТЕБЬЯНКО АРГЕНТО', 'Кухня МОНТЕБЬЯНКО', 'Кухня ДОЛОМИТА', 'Кухня ГАРДА', 'Кухня АСТИ', 'Кухня КВАТРО ГРАФИТ', 'Кухня КВАТРО БЕЛЫЙ', 'Кухня КВАТРО ПЕСОЧНЫЙ', 'Кухня МАНЧЕСТЕР ФИСТАШКА', 'Кухня МАНЧЕСТЕР ЛЕН', 'Кухня МИЛАН БЬЯНКО', 'Кухня ОКСФОРД БЕЛЫЙ ДУБ', 'Кухня ОКСФОРД ГРАФИТ', 'Кухня КАПРИ', 'Кухня ЭЛЬБА', 'Кухня КОРТИНА', 'Кухня ГЕСТИЯ', 'Кухня ДЕМЕТРА', 'Кухня АСКОТ', 'Кухня РИАЛЬТО', 'Кухня ТРИЕСТЕ', 'Кухня ВЕНЕЦИЯ', 'Кухня ФИРЕНЦЕ', 'Кухня СОРРЕНТО', 'Кухня ПОЗИТАНО', 'Кухня ВИКТОРИЯ', 'Кухня РОМАНТИКА', 'Кухня НИКА НОЧЕ', 'Кухня НИКА', 'Кухня НИКА Д’ОРО БЕЛАЯ', 'Кухня НИКА Д’ОРО БЕЖЕВАЯ', 'Кухня АФИНА АРГЕНТО', 'Кухня АФИНА ОРО', 'Кухня ТУРИН', 'Кухня ПРОВАНС ПРАЙМЕР', 'Кухня ПРОВАНС', 'Кухня ПОРТОФИНО КАПУЧИНО', 'Кухня ПОРТОФИНО БЕЛАЯ', 'Кухня АМАЛЬФИ СЕРАЯ', 'Кухня АМАЛЬФИ БЕЖЕВАЯ', 'Кухня РОЗА ДЕКАПЕ', 'Кухня РОЗА', 'Кухня ЛУКРЕЦИЯ ЗОЛОТАЯ', 'Кухня КОРИ', 'Кухня ЛУКРЕЦИЯ', 'Кухня ВЕРОНА']

воскресенье, 7 июля 2019 г.

Выполнить сортировку html таблицы до получения html кода

Получаю данные по этой ссылке. Код на python. Также использую библиотеку BeautifulSoup для последующей обработки HTML кода.
Как мне, перед получением HTML кода страницы, выполнить сортировку таблицы на сайте, например по цене?
url = 'https://coinmarketcap.com/currencies/bitcoin/#markets' html = requests.get(url).text data = get_data(html)


Ответ

Можно воспользоваться модулем Pandas
import pandas as pd
url = 'https://coinmarketcap.com/currencies/bitcoin/#markets' df = pd.read_html(url)[0]
res = (df.assign(pr_num=lambda x: pd.to_numeric(x['Price'].str.replace(r'[\$,\s\*]',''), errors='coerce')) .sort_values('pr_num', ascending=False))
результат:
In [268]: print(res) # Source Pair Volume (24h) Price Volume (%) Updated pr_num 353 354 CoinExchange CUBE/BTC $1,568,170 $13064.30 0.03% Recently 13064.30 13 14 BTCC BTC/USD $58,216,900 $7630.00 1.25% Recently 7630.00 224 225 LakeBTC BTC/USD $3,144,690 $7144.04 0.07% Recently 7144.04 251 252 Bitinka BTC/ARS $2,599,470 $7087.53 0.06% Recently 7087.53 170 171 BCEX NAS/BTC $4,433,300 $7057.71 0.09% Recently 7057.71 .. ... ... ... ... ... ... ... ... 280 281 Bit-Z XAS/BTC $2,230,820 $6297.18 0.05% Recently 6297.18 279 280 BtcTrade.im ETC/BTC $2,270,590 $6287.73 0.05% Recently 6287.73 291 292 OKEx OF/BTC $2,112,840 $6278.22 0.05% Recently 6278.22 369 370 Hotbit BZNT/BTC $1,453,500 $6272.91 0.03% Recently 6272.91 193 194 BCEX ANS/BTC $3,664,540 $5950.85 0.08% Recently 5950.85
[400 rows x 8 columns]
если нужен HTML:
res.to_html(r'c:/temp/res.html')
результат для первых 10 строк:

# Source Pair Volume (24h) Price Volume (%) Updated pr_num
353 354 CoinExchange CUBE/BTC $1,568,170 $13064.30 0.03% Recently 13064.30
13 14 BTCC BTC/USD $58,216,900 $7630.00 1.25% Recently 7630.00
224 225 LakeBTC BTC/USD $3,144,690 $7144.04 0.07% Recently 7144.04
251 252 Bitinka BTC/ARS $2,599,470 $7087.53 0.06% Recently 7087.53
170 171 BCEX NAS/BTC $4,433,300 $7057.71 0.09% Recently 7057.71
223 224 BtcTrade.im LTC/BTC $3,146,020 $7044.13 0.07% Recently 7044.13
146 147 Bit-Z GXS/BTC $5,608,050 $6958.11 0.12% Recently 6958.11
385 386 LBank PNT/BTC $1,385,290 $6904.87 0.03% Recently 6904.87
264 265 Negocie Coins BTC/BRL $2,487,080 $6898.36 0.05% Recently 6898.36
387 388 Trade By Trade DASH/BTC $1,378,990 $6894.70 0.03% Recently 6894.70

PS чтобы удалить созданный столбец pr_num
res = res.drop('pr_num', axis=1)
In [272]: res Out[272]: # Source Pair Volume (24h) Price Volume (%) Updated 353 354 CoinExchange CUBE/BTC $1,568,170 $13064.30 0.03% Recently 13 14 BTCC BTC/USD $58,216,900 $7630.00 1.25% Recently 224 225 LakeBTC BTC/USD $3,144,690 $7144.04 0.07% Recently 251 252 Bitinka BTC/ARS $2,599,470 $7087.53 0.06% Recently 170 171 BCEX NAS/BTC $4,433,300 $7057.71 0.09% Recently .. ... ... ... ... ... ... ... 280 281 Bit-Z XAS/BTC $2,230,820 $6297.18 0.05% Recently 279 280 BtcTrade.im ETC/BTC $2,270,590 $6287.73 0.05% Recently 291 292 OKEx OF/BTC $2,112,840 $6278.22 0.05% Recently 369 370 Hotbit BZNT/BTC $1,453,500 $6272.91 0.03% Recently 193 194 BCEX ANS/BTC $3,664,540 $5950.85 0.08% Recently
[400 rows x 7 columns]

пятница, 5 июля 2019 г.

Адресация по объектам BeautifulSoup

Пищу парсер на Python 2.7, используя BeautifulSoup 4. Возникла трудность.
Извлек я все элементы со страницы.
for p in allPosts: postIMG = p.find_all('img')
В итоге получилось:
Название Название 2
Как обратится к тексту? Можно как-то через точку? postIMG.alt ? Или как лучше? Как красивее всего извлечь урл картинки?


Ответ

find_all возвращает список объектов класса bs4.element.Tag и к аттрибутам элемента можно обратиться через словарь attrs
for p in allPosts: postIMG = p.find_all('img') print postIMG[0].attrs['alt'] print postIMG[0].attrs['src']
Если картинка в посте одна, то удобнее использовать метод find, вместо find_all
for p in allPosts: postIMG = p.find('img') print postIMG.attrs['alt'] print postIMG.attrs['src']

понедельник, 8 апреля 2019 г.

Получение значения аттрибута “name” тэга “input”

Как получить значение атрибута name всех тэгов input ?
То есть если был тэг

то в массиве должно быть только значение "value". Я знаю, что для div'a это можно сделать так:
titles = [div['title'] for div in soup.find_all('div', title = True)]
Но если пробую просто заменить все div на input, а title на name, то сталкиваюсь с проблемой, что input - зарезервированное слово (возможно, проблема не в этом, но все равно ничего не работает)


Ответ

Попробуйте:
input_names = [tag['name'] for tag in soup.select('input[name]')]
Проверка:
import requests from bs4 import BeautifulSoup
rs = requests.get('https://ru.stackoverflow.com/questions/830858/') root = BeautifulSoup(rs.content, 'html.parser')
input_names = [tag['name'] for tag in root.select('input[name]')] print(input_names) # ['q', '_id_', 'qualityBanWarningShown', 'referrer', ...

четверг, 21 марта 2019 г.

Выдернуть ВСЕ значения атрибута bigimg используя BeautifulSoup

Назрел такой вопрос. Только начал изучать питон, используя библиотеку BeautifulSoup задался вопросом. Есть HTML код, к примеру:
MY-520 Portable Ultrasonic Nebulizer Atomized Inhaler 520 MY-520 Portable Ultrasonic Nebulizer Atomized Inhaler 520
Мне нужно выдернуть все ссылки на большие изображения, которые находятся в атрибуте bigimg=
Написал такую строчку:
itemImages = soup.find("div", "scrollableDiv").findAll("img")
но как выдернуть именно ВСЕ значения атрибута bigimg не представляю. Может быть кто-то сталкивался с подобной проблемой, буду признателен.


Ответ

К сожалению не знаю библиотеку beautiful soap , но знаю как решить вашу проблему регекспами. допустим весь хтмль код у вас содержится в переменной html import re big_imgs = re.findall(r'bigimg="(.*?)"', html) в big_imgs у вас массив со всеми значениями внутри bigimg. например если бы приведены вами хтмль код засунуть в переменную html >>> big_imgs = re.findall(r'bigimg="(.*?)"', html) >>> big_imgs ['/uploads/201103/source-img/MY-520-Nebulizer-Atomized-Inhaler-G-44318.jpg', '/u ploads/201103/source-img/MY-520-Nebulizer-Atomized-Inhaler1298912536529-P-44318. jpg']

пятница, 1 марта 2019 г.

Как получить содержимое ссылок?

Подскажите пожалуйста как получить содержимое ссылок c BeautifulSoup(html, 'lxml')? Не сами ссылки а название! есть вот такой код:
html = urllib.request.urlopen('https://kyxni.pro/katalog/') soup = BeautifulSoup(html, 'html.parser').find('div', class_='builder-posts-wrap') for i in soup.find_all('h2', class_='post-title'): print(i)
выводит ссылки:

Кухня ЭЛЕГИЯ

Кухня ДИАНА

Кухня ТЕМЗА


а я хочу получить сами названия:
Кухня ЭЛЕГИЯ Кухня ДИАНА Кухня ТЕМЗА и т.д.
Подскажите пожалуйста как это реализовать?
И как можно открыть сохранённую страницу, что бы каждый раз сайт не грузить? Такая конструкция в коде который выше не работает
html = open('kuhni.html').read()


Ответ

а я хочу получить сами названия:
for i in soup.find_all('h2', class_='post-title entry-title'): print(i.text)
Когда нужно получить текстовое содержимое, применяйте атрибут text (только не к списку, который возвращается методом find_all).
И как можно открыть сохранённую страницу, что бы каждый раз сайт не грузить? Такая конструкция в коде который выше не работает
У меня получилось так:
html = open('kuhni.html', encoding='utf8').read()
P.S. На будущее. Приводите текст ошибок.