Как извлечь кортежи с помощью findall?

Я пытаюсь извлечь кортежи из URL, и мне удалось извлечь текст строки и кортежи, используя re.search(pattern_str, text_str), Тем не менее, я застрял, когда я пытался извлечь список кортежей с помощью re.findall(pattern_str, text_str),

Текст выглядит так:

<li>
  <a href="11111">
    some text 111
    <span class="some-class">
      #11111
    </span>
  </a>
</li><li>
  <a href="22222">
    some text 222
    <span class="some-class">
      #22222
    </span>
  </a>
</li><li>
  <a href="33333">
    some text 333
    <span class="some-class">
      #33333
    </span>
  </a>
... # repeating
... 
... 

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

text_above = "..." # this is the text above
pat_str = '<a href="(\d+)">\n(.+)\n<span class'
pat = re.compile(pat_str)
# following line is supposed to return the numbers from the 2nd line
# and the string from the 3rd line for each repeating sequence
list_of_tuples = re.findall(pat, text_above)

for t in list_of tuples:
    # supposed to print "11111 -> blah blah 111"
    print(t[0], '->', t[1])

Может быть, я пытаюсь сделать что-то странное и невозможное, может быть, лучше извлечь данные, используя примитивные манипуляции со строками... Но в случае, если существует решение?

2 ответа

Решение

Как предлагается в комментариях, используйте html-парсер, например BeautifulSoup:

from bs4 import BeautifulSoup

h = """<li>
  <a href="11111">
    some text 111
    <span class="some-class">
      #11111
    </span>
  </a>
</li><li>
  <a href="22222">
    some text 222
    <span class="some-class">
      #22222
    </span>
  </a>
</li><li>
  <a href="33333">
    some text 333
    <span class="some-class">
      #33333
    </span>
  </a>"""

soup = BeautifulSoup(h)

Вы можете получить href и previous_sibling в span:

print([(a["href"].strip(), a.span.previous_sibling.strip()) for a in soup.find_all("a")])
[('11111', u'some text 111'), ('22222', u'some text 222'), ('33333', u'some text 333')]

Или href и первый контент с якоря:

print([(a["href"].strip(), a.contents[0].strip()) for a in soup.find_all("a")])

Или с .find(text=True) чтобы получить только текст тега, а не от детей.

[(a["href"].strip(), a.find(text=True).strip()) for a in soup.find_all("a")]

Также, если вы просто хотите привязки внутри тегов списка, вы можете специально проанализировать их:

[(a["href"].strip(), a.contents[0].strip()) for a in soup.select("li a")]

Ваше регулярное выражение не учитывает пробел (отступ) между \n а также <span, (И ни пробел в начале строки, которую вы хотите захватить, но это не такая большая проблема.) Чтобы исправить это, вы можете добавить некоторые \s*:

pat_str = '<a href="(\d+)">\n\s*(.+)\n\s*<span class'
Другие вопросы по тегам