2017-04-09 1 views
1

J'ai essayé de gratter les pages suivantes (par exemple 1, 2) en utilisant BeautifulSoup pour obtenir la liste des actions pour voyager d'un endroit à Bangkok à un autre endroit.BeautifulSoup obtenir tous les liens après balise donné

Fondamentalement, je peux interroger et sélectionner la description des voyages comme suit.

url = 'http://www.transitbangkok.com/showBestRoute.php?from=Sutthawat+-+Arun+Amarin+Intersection&to=Sukhumvit&originSelected=true&destinationSelected=true&lang=en' 
route_request = requests.get(url) 
soup_route = BeautifulSoup(route_request.content, 'lxml') 
descriptions = soup_route.find('div', attrs={'id': 'routeDescription'}) 

Le code HTML de descriptions ressemble à la suivante

<div id="routeDescription"> 
... 
<br/> 
<img src="/images/walk_icon_small.PNG" style="vertical-align:middle;padding-right: 10px;margin-right: 0px;"/>Walk by foot to <b>Sanam Luang</b> 
<br/> 
<img src="/images/bus_icon_semi_small.gif" style="vertical-align:middle;padding-right: 10px;margin-right: 0px;"/>Travel to <b>Khok Wua</b> using the line(s): <b><a href="lines/bangkok-bus-line/2">2</a></b> or <a href="lines/bangkok-bus-line/15">15</a> or <a href="lines/bangkok-bus-line/44">44</a> or <a href="lines/bangkok-bus-line/47">47</a> or <a href="lines/bangkok-bus-line/59">59</a> or <a href="lines/bangkok-bus-line/201">201</a> or <a href="lines/bangkok-bus-line/203">203</a> or <a href="lines/bangkok-bus-line/512">512</a><br/> 
... 
</div> 

En gros, j'essaie d'obtenir la liste des actions et des lignes de bus pour se rendre à l'emplacement suivant (question mis à jour avec la réponse, mais encore n » ai pas t résoudre).

route_descrtions = [] 
for description in descriptions.find_all('img'): 
    action = description.next_sibling 
    to_station = action.next_sibling 
    n = action.find_next_siblings('a') 
    if 'travel' in action.lower(): 
     lines = [to_station.find_next('b').text] + [a.contents[0] for a in n] 
    else: 
     lines = [] 
    desp = {'action': action, 
      'to': to_station.text, 
      'lines': lines} 
    route_descrtions.append(desp) 

Cependant, je ne sais pas comment faire une boucle à travers les liens après chaque action (Travel to action) et ajouter à ma liste. J'ai essayé find_next('a') et find_next_siblings('a') mais n'ai pas accompli ma tâche.

Sortie

[{'action': 'Walk by foot to ', 'lines': [], 'to': 'Wang Lang (Siriraj)'}, 
{'action': 'Travel to ', 
    'lines': ['Chao Phraya Express Boat', '40', '48', '501', '508'], 
    'to': 'Si Phraya'}, 
{'action': 'Walk by foot to ', 'lines': [], 'to': 'Sheraton Royal Orchid'}, 
{'action': 'Travel to ', 
    'lines': ['16', '40', '48', '501', '508'], 
    'to': 'Siam'}, 
{'action': 'Travel to ', 
    'lines': ['BTS - Sukhumvit', '40', '48', '501', '508'], 
    'to': 'Asok'}, 
{'action': 'Walk by foot to ', 'lines': [], 'to': 'Sukhumvit'}] 

sortie souhaitée

[{'action': 'Walk by foot to ', 'lines': [], 'to': 'Wang Lang (Siriraj)'}, 
{'action': 'Travel to ', 
    'lines': ['Chao Phraya Express Boat'], 
... 

Répondre

1

Ce qui suit devrait fonctionner:

from bs4 import BeautifulSoup 
import requests 
import pprint 

url = 'http://www.transitbangkok.com/showBestRoute.php?from=Sutthawat+-+Arun+Amarin+Intersection&to=Sukhumvit&originSelected=true&destinationSelected=true&lang=en' 
route_request = requests.get(url) 
soup_route = BeautifulSoup(route_request.content, 'lxml') 
routes = soup_route.find('div', attrs={'id': 'routeDescription'}) 

parsed_routes = list() 
for img in routes.find_all('img'): 
    action = img.next_sibling 
    to_station = action.next_sibling 
    links = list() 
    for sibling in img.next_siblings: 
     if sibling.name == 'a': 
      links.append(sibling) 
     elif sibling.name == 'img': 
      break 

    lines = list() 
    if 'travel' in action.lower(): 
     lines.extend([to_station.find_next('b').text]) 
     lines.extend([link.contents[0] for link in links]) 

    parsed_route = {'action': action, 'to': to_station.text, 'lines': lines} 
    parsed_routes.append(parsed_route) 

pprint.pprint(parsed_routes) 

Ce sorties:

[{'action': 'Walk by foot to ', 'lines': [], 'to': 'Wang Lang (Siriraj)'}, 
{'action': 'Travel to ', 
    'lines': ['Chao Phraya Express Boat'], 
    'to': 'Si Phraya'}, 
{'action': 'Walk by foot to ', 'lines': [], 'to': 'Sheraton Royal Orchid'}, 
{'action': 'Travel to ', 'lines': ['16'], 'to': 'Siam'}, 
{'action': 'Travel to ', 
    'lines': ['BTS - Sukhumvit', '40', '48', '501', '508'], 
    'to': 'Asok'}, 
{'action': 'Walk by foot to ', 'lines': [], 'to': 'Sukhumvit'}] 

Votre question clé était n = action.find_next_siblings('a') parce qu'il a tous les liens au même niveau après votre image "en cours". Voyant que toutes les images et tous les liens étaient au même niveau, ce n'était pas ce que vous vouliez.

Vous pensiez probablement aux images en tant que nœuds parents des liens.Quelque chose comme:

  • img1
    • link1
  • img2
    • lien2
  • img3
    • link3
    • link4
    • link5

Cependant, en réalité, il était plus comme ce qui suit:

  • img1
  • link1
  • img2
  • lien2
  • img3
  • link3
  • link4
  • link5

Lorsque vous avez demandé les images que vous avez obtenu img1, img2 et img3 (dans cet exemple). Et quand vous avez demandé à tous les frères et sœurs du lien suivant, vous l'avez eu. Donc, si vous étiez à img2, et a demandé les frères et sœurs lien suivant vous les avez, par exemple,

  • img1
  • link1
  • img2 < Vous êtes ici, et a obtenu ...
  • lien2 < ce,
  • img3 - (pas, parce que ce n'est pas un lien)
  • link3 < cela,
  • link4 < cela, et
  • link5 < cette

J'espère que cela explique. Le changement que j'ai fait était juste de faire une boucle jusqu'à ce que vous trouviez une image et que je m'arrête là. Ainsi, votre boucle d'image externe continue à partir de là. J'ai également nettoyé une partie du code. Juste pour plus de clarté.

+0

Merci André! la solution fonctionne pour moi. Merci aussi pour la bonne explication. Déjà accepté la réponse (et le pouce en l'air)! – titipata

0

Vous pouvez essayer find_next_siblings (en utilisant Python 2.7):

import bs4 

text = '''<img src="/images/bus_icon_semi_small.gif" style="vertical-align:middle;padding-right: 10px;margin-right: 0px;"/>Travel to <b>Khok Wua</b> using the line(s): <b><a href="lines/bangkok-bus-line/2">2</a></b> or <a href="lines/bangkok-bus-line/15">15</a> or <a href="lines/bangkok-bus-line/44">44</a> or <a href="lines/bangkok-bus-line/47">47</a> or <a href="lines/bangkok-bus-line/59">59</a> or <a href="lines/bangkok-bus-line/201">201</a> or <a href="lines/bangkok-bus-line/203">203</a> or <a href="lines/bangkok-bus-line/512">512</a><br/>x`x''' 

soup = bs4.BeautifulSoup(text, 'lxml') 
img = soup.find('img') 
action = img.next_sibling 
to_station = action.next_sibling 
n = to_station.find_next_siblings('a') 
d = { 
    'action': action, 
    'to': to_station.text, 
    'buses': [a.contents[0] for a in n] 
} 

Résultats:

{'action': u'Travel to ', 'to': u'Khok Wua', 'buses': [u'15', u'44', u'47', u'59', u'201', u'203', u'512']} 
+0

Salut Yohanes, je l'ai essayé mais ça ne marche pas pour mon problème particulier. Avez-vous la solution qui fonctionne pour le HTML complet donné aussi? – titipata