2012-01-21 7 views
2

J'apprends Python - Beautiful Soup en essayant de gratter des données. J'ai une page HTML avec ce format ...Python - Extraire des liens avec des ID

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 

et ainsi de suite jusqu'à 40 de ces entrées.

Je voudrais obtenir le texte présent dans ces classes/ID dans le même ordre que sur cette page HTML.

Pour le coup d'envoi, j'ai essayé quelque chose comme ça pour obtenir la liste nom-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"}) 

Il jette Une connexion existante a été fermée de force par l'hôte distant d'erreur

Je ne idée comment résoudre ce problème. Je besoin d'aide sur deux choses:

  1. Comment réparer cette erreur
  2. Comment puis-je itérer la liste nom-1 de 1 à 40? Je ne veux pas taper soup.find(span,attrs={"id=listing-name-1"}) pour les 40 ID de plage.

Merci beaucoup!

+0

essayer 'page.read()' et voir êtes-vous en mesure de récupérer le contenu de la page – RanRag

+1

Je voudrais d'abord télécharger la page à la machine locale, puis travailler sur la partie analyse et enfin si c'est prêt, branchez le fichier distant de lecture ... – plaes

Répondre

3

Avec lxml.html vous pouvez appeler le parse directement avec une adresse URL afin de ne pas avoir à appeler le urllib. En outre, au lieu d'utiliser find ou findall vous aurez envie d'appeler xpath de sorte que vous obtenez le full expressiveness of xpath; Si vous essayez d'appeler la même expression ci-dessous en utilisant find, une erreur invalid predicate s'affichera.

#!/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 

Affichera cela, la préservation de l'ordre:

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

Pour répondre à la question dans vos commentaires à ma réponse, ce que vous voulez rechercher est le <div class="listingInfoContainer">...</div> qui contient toutes les informations que vous voulez . (le nom, l'adresse, etc.) Vous pouvez ensuite parcourir la liste des éléments div correspondant à ces critères et utiliser les expressions xpath pour extraire le reste des informations. Notez que dans ce cas j'utilise container.xpath('.//span') qui va chercher depuis le noeud courant (le container div), sinon si vous omettez le . et juste //span il commencera la recherche depuis le haut de l'arbre et vous obtiendrez une liste de tous les éléments qui correspondent, ce qui n'est pas ce que vous voulez quand vous sélectionnez le nœud du conteneur.

#!/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 

qui sort:

[{'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         ']}] 

qui est une liste (encore une fois, préserver l'ordre de la façon dont vous voulez) des dictionnaires avec les touches name et address que contiennent chacun une liste. Cette liste finale est renvoyée par text() qui préserve les caractères de nouvelle ligne \n dans le code HTML d'origine et traduit des éléments tels que <br> en un nouvel élément de liste. Un exemple de pourquoi il le fait est l'élément de la liste, Archicentre, où la représentation HTML original est:

<span class="address"> 
    Level 3, 60 Collins St 
    <br/> 
    Melbourne VIC 3000 
</span> 
+0

Quelle est la syntaxe pour extraire des liens? J'ai essayé de me moquer de votre syntaxe 'Website = tree.xpath (" // a [contient (@ id, 'websiteLink')]/href() ")' mais ça ne marche pas. –

+0

Aussi, je viens de trouver que la syntaxe 'Adresse = tree.xpath (" // span [contient (@ class, 'address')]/text() ")' récupère tout le contenu de la page qui a ''

+1

@BhavaniKannan J'ai mis à jour ma réponse pour répondre aux questions que vous aviez ici dans les commentaires. J'ai répondu à ce que je pensais être le plus gros problème que vous essayez d'obtenir avec votre question. Il existe plusieurs moyens de résoudre le problème, mais je pense que celui-ci est un moyen simple et efficace de sélectionner le sous-ensemble du document HTML qui vous intéresse, puis d'extraire les données spécifiques dont vous avez besoin de chaque répétition. section. – aculich

1

La réponse à votre deuxième partie est assez simple:

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)}) 
+0

Lattyware, merci! Il me renvoie toujours la même erreur: erreur: [Errno 10054] Une connexion existante a été forcée par l'hôte distant »Traceback a commencé à partir de' Traceback (dernier appel dernier): Fichier "F: \ Documents and Settings \ Bhavani \ Desktop \ YP.py ", ligne 6, dans soup = BeautifulSoup (page)' –

+0

@BhavaniKannan J'ai exécuté ceci et cela a bien fonctionné, donc il doit y avoir un problème dans votre environnement. –

+0

Lattyware, merci encore! Je n'ai pas la moindre idée de la raison, mais cela me jette encore cette erreur alors que cette solution lxml a bien fonctionné. Peut être, pouvez-vous me diriger vers ce que je devrais vérifier dans mon environnement? Je suis sur Windows XP SP2 en utilisant Python 2.7 (Idle) –

1

Votre premier problème semble sans rapport avec python. Essayez d'imprimer page.read() et voyez si cela donne une sortie. Essayez d'ouvrir la page avec votre webbrowser et voir si elle charge.

Quant à votre deuxième problème, vous pouvez passer une expression régulière pour 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) 

Les impressions ci-dessus toutes les annonces sur ma machine afin que votre premier problème est certainement en dehors de votre code.

+0

Rob, La page se charge très bien avec mon navigateur Web (Firefox) mais page.read() renvoie une erreur. Ce que je devrais faire? –

Questions connexes