Python - Извлечение ссылок с идентификаторами - PullRequest
2 голосов
/ 21 января 2012

Я изучаю Python - Beautiful Soup, пытаясь очистить данные. У меня есть HTML-страница в этом формате ...

span id listing-name-1
span class address
span preferredcontact="1"
a ID websiteLink1

span id listing-name-2
span class address
span preferredcontact="2"
a ID websiteLink2

span id listing-name-3
span class address
span preferredcontact="3"
a ID websiteLink3

и т. Д. До 40 таких записей.

Я хотел бы получить текст, который присутствует внутри этих классов / идентификаторов в том же порядке, в каком они находятся на этой HTML-странице.

Чтобы начать, я попробовал что-то вроде этого, чтобы получить list-name-1

import urllib2
from BeautifulSoup import BeautifulSoup

page = urllib2.urlopen("http://www.yellowpages.com.au/search/listings?clue=architects&locationClue=New+South+Wales&x=45&y=12")

soup = BeautifulSoup(page)

soup.find(span,attrs={"id=listing-name-1"})

Выдает Существующее соединение было принудительно закрыто удаленным хостом Ошибка

Понятия не имею, как это исправить. Мне нужна помощь в двух вещах:

  1. Как исправить эту ошибку
  2. Как я могу выполнить итерацию list-name-1 от 1 до 40? Я не хочу вводить soup.find(span,attrs={"id=listing-name-1"}) для всех 40 идентификаторов пролета.

Спасибо!

Ответы [ 3 ]

3 голосов
/ 21 января 2012

С помощью lxml.html вы можете позвонить parse напрямую с помощью URL, чтобы вам не пришлось звонить urllib самостоятельно. Кроме того, вместо использования find или findall вы захотите вызвать xpath, чтобы вы получили полную выразительность xpath ; если вы попытались вызвать то же выражение ниже, используя find, он вернет ошибку invalid predicate.

#!/usr/bin/env python

import lxml.html

url = "http://www.yellowpages.com.au/search/listings?clue=architects&locationClue=New+South+Wales&x=45&y=12"
tree = lxml.html.parse(url)
listings = tree.xpath("//span[contains(@id,'listing-name-')]/text()")
print listings

выведет это, сохранив порядок:

['Cape Cod Australia Pty Ltd',
'BHI',
'Fibrent Pty Ltd Building & Engineering Assessments',
 ...
'Archicentre']

Чтобы ответить на вопрос в ваших комментариях к моему ответу, вам нужно найти <div class="listingInfoContainer">...</div>, который содержит всю необходимую вам информацию. (имя, адрес и т. д.). Затем вы можете просмотреть список элементов div, соответствующих этим критериям, и использовать выражения xpath для извлечения остальной информации. Обратите внимание, что в этом случае я использую container.xpath('.//span'), который будет искать с текущего узла (контейнера div), в противном случае, если вы пропустите . и просто наберете //span, он начнет поиск с вершины дерева и вы получите список всех совпадающих элементов, а это не то, что вам нужно после выбора узла контейнера.

#!/usr/bin/env python

import lxml.html

url = "http://www.yellowpages.com.au/search/listings?clue=architects&locationClue=New+South+Wales&x=45&y=12"
tree = lxml.html.parse(url)
container = tree.xpath("//div[@class='listingInfoContainer']")
listings = []
for c in container:
    data = {}
    data['name'] = c.xpath('.//span[contains(@id,"listing")]/text()')
    data['address'] = c.xpath('.//span[@class="address"]/text()')
    listings.append(data)

print listings

который выводит:

[{'name': ['Cape Cod Australia Pty Ltd'], 
  'address': ['4th Floor 410 Church St, North Parramatta NSW 2151']}, 
 {'name': ['BHI'], 
  'address': ['Suite 5, 65 Doody St, Alexandria NSW 2015']}, 
 {'name': ['Fibrent Pty Ltd Building & Engineering Assessments'], 
  'address': ["Suite 3B, Level 1, 72 O'Riordan St, Alexandria NSW 2015"]}, 
  ...
 {'name': ['Archicentre'], 
  'address': ['\n                                         Level 3, 60 Collins St\n                                         ',
              '\n                                         Melbourne VIC 3000\n                                    ']}]

- это список (опять же, сохраняя порядок, который вы хотели) словарей с ключами name и address, каждый из которых содержит список. Этот окончательный список возвращается text(), который сохраняет символы новой строки \n в оригинальном HTML и переводит такие вещи, как <br>, в новый элемент списка. Примером того, почему это так, является элемент списка Archicentre, в котором исходное представление HTML имеет вид:

<span class="address">
     Level 3, 60 Collins St
     <br/>
     Melbourne VIC 3000
</span>
1 голос
/ 21 января 2012

Ваша первая проблема не связана с питоном. Попробуйте напечатать page.read() и посмотрите, даст ли это какой-либо вывод. Попробуйте открыть страницу с помощью веб-браузера и посмотреть, загружается ли она.

Что касается вашей второй проблемы, вы можете передать регулярное выражение findAll:

import re
import urllib2

from BeautifulSoup import BeautifulSoup

page = urllib2.urlopen("http://www.yellowpages.com.au/search/listings?clue=architects&locationClue=New+South+Wales&x=45&y=12")

soup = BeautifulSoup(page)

listing_names = re.compile('listing-name-[0-9]+')
listings = soup.findAll('span', id=listing_names)
print(listings)

Приведенное выше распечатывает все списки на моем компьютере, поэтому ваша первая проблема определенно находится за пределами вашего кода.

1 голос
/ 21 января 2012

Ответ на вашу вторую часть достаточно прост:

import urllib2
from BeautifulSoup import BeautifulSoup

page = urllib2.urlopen("http://www.yellowpages.com.au/search/listings?clue=architects&locationClue=New+South+Wales&x=45&y=12")

soup = BeautifulSoup(page)

for num in range(1, 41):
    soup.find("span", attrs={"id": "listing-name-"+str(num)})
...