LINUX.ORG.RU

Парсинг xml на Python3.5 с помощью bs4 [проблемы с кодировкой]

 , , , ,


1

1

Нужно, распарсить xml в питоне, но назло мне появились проблемы с кодировкой.

Сначала сделал запрос к API (тут все норм)

import requests
#Переменные с параметрами для запроса
game = 'insurg'
count = '100'
gameme_page = 'http://stats.whiskey-server.ru'
#Сам запрос
req = gameme_page + '/api/playerlist/' + game + '?limit=' + count
r = requests.get(req)
print(r.encoding)
resp = r.text.encode('utf-8')
print(resp)

Но вот как дело дошло до парсинга тут появились проблемы

Вот такой код, выдает ошибку кодировки UnicodeEncodeError: 'ascii' codec can't encode character

# -*- coding: utf-8 -*-
import requests
from bs4 import BeautifulSoup

game = 'insurg'
count = '100'
gameme_page = 'http://stats.whiskey-server.ru'
req = gameme_page + '/api/playerlist/' + game + '?limit=' + count
r = requests.get(req)
resp = r.text.encode("utf-8")
soup = BeautifulSoup(resp, 'xml')
print (soup.prettify())

Подставил .encode(«utf-8») к prettify

# -*- coding: utf-8 -*-
import requests
from bs4 import BeautifulSoup

game = 'insurg'
count = '100'
gameme_page = 'http://stats.whiskey-server.ru'
req = gameme_page + '/api/playerlist/' + game + '?limit=' + count
r = requests.get(req)
resp = r.text
soup = BeautifulSoup(resp, 'xml')
print (soup.prettify().encode("utf-8"))
и вроде бы все заработало, но теперь во всех строчках появились \n

'<?xml version=«1.0» encoding=«utf-8»?>\n<gameME>\n <vendor>\n <label>\n gameME\n </label>\n <webpage>\n ......

Объясните пожалуйста как распарсить все это по-человечески.

P.s Если что, для доступа к GameME API никаких токенов не нужно, так что у вас вполне получится опробовать код самим


Кстати, немного оффтопика. А Питон-то вообще умеет парсить (не самому писать регулярки, а адекватно) xml стандартными средствами ? Вот csv и json умеет. Я серьезно не помню чем, но прежде чем идти в гугл тут напишу. даже java (которая для парсинга и автоматизации в целом подходит сильно меньше ИМХО(!)) вродебы (тут я не уверен, ибо не джавист, а только сталкиваюсь по долгу службы) имеет встроеный SAXParser

По сабжу. Имеет смысл попробовать chardet.

Dred ★★★★★ ()

В r.text уже содержится текст для которого requests угадал кодировку. Чистый байтовый ответ находится в r.content.

А для парсинга xml рекомендую lxml.

PolarFox ★★★★★ ()
Ответ на: комментарий от iljuase

Там на самом деле есть зависимость от того, в какой кодировке (внезапно) емулятор терминала работает (на с таким я только на винде сталкивался), кодировка скрипта (хотя это маразм и редкость) и кодировка которая указана в заголовке скрипта

Dred ★★★★★ ()
Ответ на: комментарий от Hinex

А шрифт ты не менял в консоли? Поставь Monospace. И попробуй запустить в другом эмуляторе терминала.

Просто такая ошибка у меня возникала на Windows и фиксилась она заменой шрифтов в консоли.

iljuase ★★★ ()
Ответ на: комментарий от Hinex

оставляя \n

было нормальное решение, но я его, конечно, не помню. Но можно попробовать что-то вроде .encode().decode('unicode_escape')

Dred ★★★★★ ()
Ответ на: комментарий от iljuase

У меня виртуалка, подрубаюсь через ssh.

Не делаю на винде, так как ней поставить нужный пакет целое приключение (какие-то траблы с компиляцией, получается только когда есть .whl)

Сейчас пробую, ранее мне посоветованный r.content + lxml, вроде бы получается

Hinex ()
Ответ на: комментарий от Hinex

lxml

разве BS и так его не использует ?

У меня никаких ошибок. Чини окружение. А заодно покажи как в файл писал. Переносы на месте.

Dred ★★★★★ ()
Последнее исправление: Dred (всего исправлений: 1)
Ответ на: комментарий от Hinex

.encode('utf-8')

откуда это вообще ? Ну если так охота в байтах писать - то надо 'wb' ставить. вместо 'w'

говорю же, чини окружение. У меня этих ошибок нет. Запрос из ОП-поста взял Кстати, эта хрень чаще всего появляется у меня в оффтопике из-за дибильной cp866

Dred ★★★★★ ()
Ответ на: комментарий от Hinex

линуксах

тебе тут народ прямым текстом вещает - в (этих наших) линуксах все работает. Проблема (скорее всего) в терминале винды.

Кодировку не utf-8 пробуй, а cp866(или windows-866). На крайняк cp1251, но это уж врятли.

Dred ★★★★★ ()
Ответ на: комментарий от Hinex

Ещё нужно шрифты поменять и в консоли Windows написать Chcp 65001. Ну может Chcp 65001 не обязательно, но я писал.

Только я не знаю, как это в Putty сделать. Или в настройках Putty поковыряйся, может там есть опция для смены кодировки консоли. Нужно utf8.

iljuase ★★★ ()
Ответ на: комментарий от Dred

Вот этот код записывает нормальный xml, теперь осталось понять как вытащить из него нужные элементы

# -*- coding: cp866 -*-
import requests
from bs4 import BeautifulSoup
from lxml import etree

game = 'insurg'
count = '100'
gameme_page = 'http://stats.whiskey-server.ru'
req = gameme_page + '/api/playerlist/' + game + '?limit=' + count
r = requests.get(req)
resp = r.text
soup = BeautifulSoup(resp, 'xml')
with open('l.xml', 'wb') as f:
    f.write(soup.prettify().encode('utf-8'))
tree = etree.parse('l.xml') # Парсинг файла
playerlist = tree.xpath('/gameME/playerlist/player')
for player in playerlist: # Перебираем элементы
    print (player.tag, player.keys(), player.values())
Вывод (что-то он мне не нравится):
player [] []
player [] []
player [] []
player [] []
player [] []
player [] []
player [] []
player [] []
player [] []

Hinex ()
Ответ на: комментарий от Hinex

Так, иди уже доки читай. Тут уж совсем как-то.

Во-первых, ты определись чем парсить будешь, BS-ом или чистым lxml. Если решил что lxml-ом, то зачем в BS файл скармливать и тд. Во-вторых, нахрена писать файл, потом открывать и парсить его ? В-третьих, у ТЕГа в xml есть «дети», а есть «параметры». Если ты по xpath достал ТЕГ, это не значит что все его «дети» сложил в милый словарик. Они тоже ТЕГи и их надо парсить, просто делать это сильно легче (А если доки открыть, так можно тонну методов для этого найти, один только getchildren, возвращающий всех детей чего стоит). А эти ключи и значения, которые ты так пытаешься просмотреть нужны для праметров xml-тегов, который рядом с именем ТЕГа обычно пишутся.

Dred ★★★★★ ()
Ответ на: комментарий от Dred

От записи в файл и bs4 избавился

Еле еле разобравшись с доками (мог бы и решения подкинуть,но все равно спасибо за наставление на путь верный) все таки получилось то чего я хотел http://prntscr.com/c6l257 .

Плюс тебе в карму за помощь чайнику и конечно же большое спасибо :)

Hinex ()
Ответ на: комментарий от iljuase

Может и говнокод, но работает и ладно

# -*- coding: cp866 -*-
import requests
from lxml import etree
game = 'insurg'
count = '100'
steam_ids = []
gameme_page = 'http://stats.whiskey-server.ru'
req = gameme_page + '/api/playerlist/' + game + '?limit=' + count
r = requests.get(req)
resp = r.text.encode('utf-8')
tree = etree.XML(resp)
playerlist = tree.xpath('/gameME/playerlist/player')
for player in playerlist:
    print (player.find('rank').text + ' ---- ' + player.find('uniqueid').text)
    steam_ids.append(player.find('uniqueid').text)
#Дальше steam_ids в файлик, но я еще не написал

Hinex ()

python3
encode

Да ну нафиг.

anonymous ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.