2012-01-29 15 views
5

używam moduł BeautifulSoup aby zaznaczyć cały href z HTML w ten sposób:Python moduł BeautifulSoup wydobywające kotwice href

def extract_links(html): 
    soup = BeautifulSoup(html) 
    anchors = soup.findAll('a') 
    print anchors 
    links = [] 
    for a in anchors: 
    links.append(a['href']) 
    return links 

ale kiedyś nie udało przez ten komunikat o błędzie:

Traceback (most recent call last): 
File "C:\py\main.py", line 33, in <module> 
urls = extract_links(page) 
File "C:\py\main.py", line 11, in extract_links 
links.append(a['href']) 
File "C:\py\BeautifulSoup.py", line 601, in __getitem__ 
return self._getAttrMap()[key] 
KeyError: 'href' 

Odpowiedz

5

nie wszystkie kotwicy tagi będą miały atrybut href. Przed próbą uzyskania dostępu do tego atrybutu należy sprawdzić, czy anchor ma href.

if a.has_key('href') 
    links.append(a['href']) 

Po sprawdzeniu niektórych uwag, uważam, że jest to najbardziej pytonowy sposób postępowania w tej sprawie.

+0

Dzięki, ale teraz IR zwrócić ten komunikat o błędzie: Traceback (najnowsza wezwanie ostatni): pliku „C: \ py \ main .py ", linia 34, w urls = extract_links (strona) Plik" C: \ py \ main.py ", wiersz 11, w linkach do wyciągów jeśli" href "w a.keys(): TypeError: ' Obiekt NoneType nie jest dostępny na żądanie. – Michal

+0

@micheal Umieszczasz znaczniki 'a' w słowniku, które nie mają atrybutów' href'. Zamiast żądać od słownika kasowania znaczników, które mogą, ale nie muszą dawać atrybutu 'href', zapytaj danych, czy to * przed * umieszczeniem ich w słowniku. – Droogans

+0

Myślę, że nowym błędem jest to, że węzeł BeautifulSoup nie jest słownikiem, więc 'keys' nie jest tym, czego oczekujesz. –

0

pythonowy sposobem byłoby coś takiego:

for a in anchors: 
    try: 
     links.append(a['href']) 
    except KeyError: 
     pass 

To po prostu pomija żadnych <a> tagów bez href.

+1

Myślę, że 'has_key()' jest bardziej Pythonic niż przy użyciu błędów dla logiki, ale ludzie wydają się nie zgadzać o tym w społeczności. –

+0

@MattLuongo: To zależy od tego, co robisz. Uważam, że najlepiej wyrazić to jako "uzyskaj adres każdego linku, a jeśli nie ma linku, nieważne", a nie "sprawdź, czy każdy link ma adres, a jeśli tak, to". Nie pomaga to, że 'has_key' jest przestarzałe dla słowników, ale' in' nie robi tego samego dla węzłów BS. –

+0

Domyślam się, że właśnie dlatego 'Tag' nie jest potomkiem' dyktatu'. Tak czy inaczej, wycofanie nie jest zbyt istotne z tego powodu. –

2

Spróbuj tego.

links = [a['href'] for a in anchors if a.has_key('href')] 

Lub, jeśli wolisz mutować istniejącej listy

links = [] 
#... 
links.extend(a['href'] for a in anchors if a.has_key('href')) 
+0

Nice one-liner. – tjarratt

+0

Lub, jak wolą docs, 'if 'href' in a' :) – Gabriel

+0

@Gabriel doktorzy mogą go preferować, ale rozważ to. 's = BeautifulSoup (' href'); "href" w s.findAll ("a") [0] "oznacza" True ". 'has_key' nie jest tak nieszczelny. –

0

Trzeba rzucić a.attrs do dict pierwszej, a następnie uzyskać dostęp do elementu.

links.append(dict(a.attrs)['href']) 
+0

Erm, myślę, że masz na myśli 'links.append (dict (a.attrs) ['href'])' ..? Ale to nie obsługuje przypadku, w którym są znaczniki z 'href's. –

+0

Masz na myśli * bez * 'href's? Masz rację. Moje osobiste doświadczenie pokazuje, że muszę rzucać. – 0605002

+0

Ha, * bez, dzięki. Chodzi mi o to, że powyższy kod nie rzuca 'a.attrs' na' dict', rzuca 'a.attrs ['href']' na 'dict', co podnosi' TypeError'. –

2

soup.findAll() zwraca listę "tagów", które zawierają słowniki atrybutów. Musisz więc wyodrębnić jego atrybuty i pracować nad nimi.

Biorąc przykład i modyfikacji, jest to kod, który działa:

def extract_links(html): 
    soup = BeautifulSoup(html) 
    anchors = soup.findAll('a') 
    print anchors 
    links = [] 
    for a in anchors: 
    if a.attrs.has_key('href'): 
     links.append(a['href']) 
return links