Найти - Пользователи
Полная версия: Распарсить текст с помощью рег. выражений
Начало » Python для новичков » Распарсить текст с помощью рег. выражений
1 2
Viktor1703
Имеется такой текст

<div class="b-content-item__title">
    <a href="http://pogoda.yandex.ru/nalchik/"class="b-link">Погода</a>
    <a href="http://pogoda.yandex.ru/nalchik/"title="облачно"class="b-weather__icon_link">
        <i class="b-inline b-weather__icon b-weather__icon_ovc"></i>
    </a>
    <a href="http://pogoda.yandex.ru/nalchik/"class="b-link_black_novisit">+11 °С</a>
</div>
<div class="b-weather__info">
    <a href="http://pogoda.yandex.ru/nalchik/"class="b-link_black_novisit">ночью&nbsp;+9</a>
    <a href="http://pogoda.yandex.ru/nalchik/"class="b-link_black_novisit">утром&nbsp;+7</a>
</div>

получаю я его с Yandex.ru, как проще всего вытащить значения:

облачно
+11 °С
ночью&nbsp;+9
утром&nbsp;+7

нужен только шаблон, я в Python новичёк и много не знаю, по этому решил и код показать, может поправите меня или посоветуете как лучше сделать то или иное (Python v2.7.3).

import urllib2, re, time
class Weather(object):
    def __init__(self):
        self.__weather__ = []
        self.__rgst__ = urllib2.Request('http://www.yandex.ru/')
        self.__page__ = urllib2.urlopen(self.__rgst__)
        self.__read__ = self.__page__.read()
        self.__page__.close()
        self.__main__ = re.findall(r'<div class=["|\']b-content-item__title["|\']>(.*?)</div>', self.__read__)
        self.__sts__  = re.findall(r'title=["|\'](.*?)["|\']', self.__main__[0])
        self.__now__  = re.findall(r'<a href=["|\'].*?["|\'].*class=["|\']b-link_black_novisit["|\']>(.*?)</a>', self.__main__[0])
        self.__weather__.append(self.__sts__[0].decode('utf-8'))
        self.__weather__.append(self.__now__[0].decode('utf-8'))
        self.__main__ = re.findall(r'<div class=["|\']b-weather__info["|\']>(.*?)</div>', self.__read__)
        for data in re.findall(r'<a href=["|\'].*?["|\'].*?class=["|\']b-link_black_novisit["|\']>(.*?)</a>', self.__main__[0]):
            self.__weather__.append(data.replace('&nbsp;', ' ').decode('utf-8'))
    def get(self):
        return self.__weather__
weather = Weather()
for i in weather.get():
    print(i)
time.sleep(5)
doza_and
Viktor1703
как проще
Проще как у страуса, потратить день на то чтобы изучить lxml а потом за 2 минуты долететь. Регулярки дают более быстродействующий код (обычно) и проще изучаются, но не всегда удобны.

Для известного контекста и разового применения подойдет и неполный разбор (поленился знаки затаскивать)
print re.search(ur'([ \+\-]*\d+) °С',s).group(1)
print re.search(ur'ночью&nbsp;([ \+\-]*\d+)',s).group(1)
print re.search(ur'утром&nbsp;([ \+\-]*\d+)',s).group(1)
>>> 
11
9
7
Viktor1703
doza_and, Вы думаете что через lxml будет удобнее? по мне так регулярки самое то… Попробуйте посмотреть исходный код главной страницы yandex, он не структурирован а написан в одну строчу.
doza_and
Если страницы разнообразные и сложные или есть повышенные требования к надежности парсинга то однозначно lxml. А тут можно даже и упростить.
Я для себя решил так - регулярки меньше 80 символов тогда регулярки если больше то парсеры
lxml если чтото специфическое то coco или pyparsing (тут выбор от требований переносить на другие языки).
Что касается советов то тут класс избыточен, достаточно функции возвращающей словарь. Ведь вам не нужны промежуточные результаты после завершения парсинга?
def get_yandex_weather():
    return [{"ночью":t_n,"днем":t_d,...},{},...]
Еще одно - двойные подчеркивания в именах с обеих сторон это зверство зарезервированное для системных нужд питона. можете наступить на грабли.
Viktor1703
doza_and, понял Вас, постараюсь разобраться с lxml, попробую разные варианты, благодарю за советы.

P.S. Не заметил что Вы добавили пример кода в первом Вашем сообщении, он как раз кстати, не знал о такой конструкции, думаю он мне подайдёт
Viktor1703
Может пригодится кому, у меня получилось так:

# -*- coding: cp1251 -*-
import urllib2, re, time
def Weather():
    result = {1 : 'Unknown', 2 : 'Unknown', 3 : 'Unknown', 4 : 'Unknown', 5 : 'Unknown'}
    try:
        page = urllib2.urlopen(urllib2.Request('http://www.yandex.ru/'))
        read = page.read()
        try:
            this = re.search(r'<div class="b-content-item__title">.*?<a href="http://pogoda.yandex.ru/(.*?)[/]".*?title="(.*?)".*?>.*?</a>.*?<a.*?>(.*?)</a>.*?</div>', read)
            if (this and (len(this.groups()) == 3)):
                result[1] = this.group(1).decode('utf-8')
                result[2] = this.group(2).decode('utf-8')
                result[3] = this.group(3).decode('utf-8')
        finally:
            del this
        try:  
            time = re.search(r'<div class="b-weather__info">.*?<a.*?>(.*?)</a>.*?<a.*?>(.*?)</a>.*?</div>', read)
            if (time and (len(time.groups()) == 2)):
                result[4] = time.group(1).replace('&nbsp;', ' ').decode('utf-8')
                result[5] = time.group(2).replace('&nbsp;', ' ').decode('utf-8')
        finally:
            del time
    finally:
        page.close()
    return result
we = Weather()
print(we[1]) # город
print(we[2]) # статус погоды
print(we[3]) # температура сейчас
print(we[4]) # температура через несколько часов
print(we[5]) # температура через пол дня
#for i in we:
#    print(we[i])
time.sleep(60)

doza_and, с такой конструкцией не хочет работать

print re.search(ur'([ \+\-]*\d+) °С',s).group(1)
print re.search(ur'ночью&nbsp;([ \+\-]*\d+)',s).group(1)
print re.search(ur'утром&nbsp;([ \+\-]*\d+)',s).group(1)

дело в том что Python прикручен к MVS2010, если я ставлю # -*- coding: utf-8 -*-, то IDE начинает ругаться на строки с “u” и подчёркиваются, с cp1251 всё отлично. И ещё раз прошу взглянуть на код, может где - то, что - то лишнее, или может добавить чего.
py.user.next
>>> import lxml.html
>>> 
>>> s = """
... <div class="b-content-item__title">
...     <a href="http://pogoda.yandex.ru/nalchik/"class="b-link">Погода</a>
...     <a href="http://pogoda.yandex.ru/nalchik/"title="облачно"class="b-weather__icon_link">
...         <i class="b-inline b-weather__icon b-weather__icon_ovc"></i>
...     </a>
...     <a href="http://pogoda.yandex.ru/nalchik/"class="b-link_black_novisit">+11 °С</a>
... </div>
... <div class="b-weather__info">
...     <a href="http://pogoda.yandex.ru/nalchik/"class="b-link_black_novisit">ночью&nbsp;+9</a>
...     <a href="http://pogoda.yandex.ru/nalchik/"class="b-link_black_novisit">утром&nbsp;+7</a>
... </div>
... """
>>> 
>>> html = lxml.html.fromstring(s)
>>> tup = html[0][2].text, html[1][0].text, html[1][1].text
>>> print(tup)
('+11 °С', 'ночью\xa0+9', 'утром\xa0+7')
>>> print(*tup, sep=':')
+11 °С:ночью +9:утром +7
>>>
Viktor1703
py.user.next, не плохо, только я получаю не этот кусочек кода, а весь код страницы, в ней всё в одну строку, для примера:

<html><head></head><script></script><body><div></div></body></html>

мне трудно будет просто найти уровень вложенности

<div class="b-content-item__title">
</div>

хотя, можно с помощью регулярки извлечь нужный мне кусок кода, и с помощью Вашего примера работать с ним, спасибо за пример.
py.user.next
Viktor1703
только я получаю не этот кусочек кода, а весь код страницы, в ней всё в одну строку
lxml не опирается на то, одна там строка или много строк, она проводит синтаксический анализ языка html, используя его грамматику (браузер точно так же делает)

Viktor1703
хотя, можно с помощью регулярки извлечь нужный мне кусок кода
а вот регулярные выражения работают просто с текстом, поэтому они не отличают теги от нетегов
оно не отличит строку от тега
<div class="b-content-item__title">
alert('<div class="b-content-item__title">');
поэтому их не используют для разбора

Viktor1703
мне трудно будет просто найти уровень вложенности
эти теги div легко найти; обычно ищешь родительские теги, которые содержат нужные, а потом берёшь их дочерние элементы
там есть методы разные для поиска: есть, к примеру, итератор по узлам, ты можешь брать узел, рассматривать его как корневой узел и брать уже его итератор по узлам
вариантов много
.xpath() поддерживает широкие возможности просмотра атрибутов (может выполнять функции для анализа атрибутов, например, отыскивать имена классов, начинающиеся на такую-то букву или слово)
doza_and
# -*- coding: cp1251 -*-
import urllib2, re, time
def Weather():
#    result = {1 : 'Unknown', 2 : 'Unknown', 3 : 'Unknown', 4 : 'Unknown', 5 : 'Unknown'}
-> result = {}
    try:
        page = urllib2.urlopen(urllib2.Request('http://www.yandex.ru/'))
        read = page.read()
        try:
            this = re.search(r'<div class="b-content-item__title">.*?<a href="http://pogoda.yandex.ru/(.*?)[/]".*?title="(.*?)".*?>.*?</a>.*?<a.*?>(.*?)</a>.*?</div>', read)
-> спорный вопрос - но можно множество проверок убрать и просто ловить Эксепшены.
            if (this and (len(this.groups()) == 3)):
                result[1] = this.group(1).decode('utf-8')
                result[2] = this.group(2).decode('utf-8')
                result[3] = this.group(3).decode('utf-8')
        finally:
            del this
-> работает сборщик мусора del не обязателен а иногда и вреден
        try:  
            time = re.search(r'<div class="b-weather__info">.*?<a.*?>(.*?)</a>.*?<a.*?>(.*?)</a>.*?</div>', read)
            if (time and (len(time.groups()) == 2)):
                result[4] = time.group(1).replace('&nbsp;', ' ').decode('utf-8')
                result[5] = time.group(2).replace('&nbsp;', ' ').decode('utf-8')
        finally:
            del time
    finally:
        page.close()
    return result
we = Weather()
-> вместо кучи принтов пойдет pprint we
print(we[1]) # город
print(we[2]) # статус погоды
print(we[3]) # температура сейчас
print(we[4]) # температура через несколько часов
print(we[5]) # температура через пол дня
#for i in we:
#    print(we[i])
time.sleep(60)-> это так понимаю для вижуала  в c++ можно жать не f5 а чтото типа ctrl f5 или shift точно не помню - и консоль не закроется.

Если вы хотите тщательно следить за освобождением ресурсов используйте конструкцию with
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB