如何使用Python从HTML中获取href链接?

59
import urllib2

website = "WEBSITE"
openwebsite = urllib2.urlopen(website)
html = getwebsite.read()

print html

目前为止一切都很好。

但是我只想从纯文本HTML中获取href链接。我该如何解决这个问题?

10个回答

129

试试使用Beautifulsoup

from BeautifulSoup import BeautifulSoup
import urllib2
import re

html_page = urllib2.urlopen("http://www.yourwebsite.com")
soup = BeautifulSoup(html_page)
for link in soup.findAll('a'):
    print link.get('href')

如果您只想要以 http:// 开头的链接,那么您应该使用:

soup.findAll('a', attrs={'href': re.compile("^http://")})
在Python 3中使用BS4应该这样写:
from bs4 import BeautifulSoup
import urllib.request

html_page = urllib.request.urlopen("http://www.yourwebsite.com")
soup = BeautifulSoup(html_page, "html.parser")
for link in soup.findAll('a'):
    print(link.get('href'))

BeautifulSoup 无法自动关闭meta标签。这会导致 DOM 模型无效,不能保证您能找到您要查找的内容。 - Anthony
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - swdev
并不是所有的链接都包含 http。例如,如果您编写网站以删除协议,则链接将以 // 开头。这意味着使用加载网站的任何协议(http:https:)。 - reubano
8
最近看到这个回答的人,请注意,Python 3中不再支持BeautifulSoup3,最新版本是BeautifulSoup4,你可以使用from bs4 import BeautifulSoup进行导入。 - Jack

36

你可以使用 HTMLParser 模块。

代码可能会像这样:

from HTMLParser import HTMLParser

class MyHTMLParser(HTMLParser):

    def handle_starttag(self, tag, attrs):
        # Only parse the 'anchor' tag.
        if tag == "a":
           # Check the list of defined attributes.
           for name, value in attrs:
               # If href is defined, print it.
               if name == "href":
                   print name, "=", value


parser = MyHTMLParser()
parser.feed(your_html_string)

注意: 在Python 3.0中,HTMLParser模块已更名为html.parser。2to3工具将在将您的源代码转换为3.0时自动适应导入。


我逐渐意识到,如果一个链接包含特殊的HTML字符,例如&,它将被转换为其文本表示形式,例如在这种情况下是&。你如何保留原始字符串? - swdev
1
我最喜欢这个解决方案,因为它不需要外部依赖。 - DomTomCat
1
@swdev - 我知道这有点晚了几年,但是 URL 编码/解码就是处理这个的方法。 - StingyJack
@Stephen 如何在标签表内查找ahref链接 - Ayesha

15

使用Beautiful Soup HTML解析库。

http://www.crummy.com/software/BeautifulSoup/

你需要像这样操作:

import BeautifulSoup
soup = BeautifulSoup.BeautifulSoup(html)
for link in soup.findAll("a"):
    print link.get("href")

谢谢!但请使用 link 而不是 a - Evgenii

10

对于这个特定的任务,使用BS4似乎有些浪费。

尝试使用:

website = urllib2.urlopen('http://10.123.123.5/foo_images/Repo/')
html = website.read()
files = re.findall('href="(.*tgz|.*tar.gz)"', html)
print sorted(x for x in (files))

我在http://www.pythonforbeginners.com/code/regular-expression-re-findall找到了这个巧妙的代码片段,对于我的需求很好用。

我只在提取网页文件夹中的文件列表方面进行了测试,例如:

enter image description here

我得到了一个按URL排序的文件\文件夹列表。


6
这个回答晚了,但对于最新的Python用户来说,它仍然适用:
from bs4 import BeautifulSoup
import requests 


html_page = requests.get('http://www.example.com').text

soup = BeautifulSoup(html_page, "lxml")
for link in soup.findAll('a'):
    print(link.get('href'))

不要忘记安装“requests”、“BeautifulSoup”包和“lxml”。使用.get()方法后跟.text,否则会抛出异常。使用“lxml”可以消除对要使用的解析器的警告。您也可以选择使用适合您情况的“html.parser”。

6
使用Python 3中的requests和BeautifulSoup:
import requests 
from bs4 import BeautifulSoup


page = requests.get('http://www.website.com')
bs = BeautifulSoup(page.content, features='lxml')
for link in bs.findAll('a'):
    print(link.get('href'))

5

可能与真正的专家相比,我的回答有所不足,但使用一些简单的数学、字符串分割、查找和urllib,这个小脚本将创建一个包含链接元素的列表。我测试了谷歌,输出似乎是正确的。希望能帮到你!

import urllib
test = urllib.urlopen("http://www.google.com").read()
sane = 0
needlestack = []
while sane == 0:
  curpos = test.find("href")
  if curpos >= 0:
    testlen = len(test)
    test = test[curpos:testlen]
    curpos = test.find('"')
    testlen = len(test)
    test = test[curpos+1:testlen]
    curpos = test.find('"')
    needle = test[0:curpos]
    if needle.startswith("http" or "www"):
        needlestack.append(needle)
  else:
    sane = 1
for item in needlestack:
  print item

5
这是@stephen答案的简化版本。
import html.parser
import itertools
import urllib.request

class LinkParser(html.parser.HTMLParser):
    def reset(self):
        super().reset()
        self.links = iter([])

    def handle_starttag(self, tag, attrs):
        if tag == 'a':
            for (name, value) in attrs:
                if name == 'href':
                    self.links = itertools.chain(self.links, [value])


def gen_links(stream, parser):
    encoding = stream.headers.get_content_charset() or 'UTF-8'
    for line in stream:
        parser.feed(line.decode(encoding))
        yield from parser.links

使用方法如下:

>>> parser = LinkParser()
>>> stream = urllib.request.urlopen('https://dev59.com/WHA75IYBdhLWcg3w1s32')
>>> links = gen_links(stream, parser)
>>> next(links)
'//stackoverflow.com'

3
这个答案与其他使用requestsBeautifulSoup的答案类似,但使用列表推导式。
由于find_all()是Beautiful Soup搜索API中最常用的方法,您可以使用soup("a")作为soup.findAll("a")的快捷方式,并使用列表推导式:
import requests
from bs4 import BeautifulSoup

URL = "http://www.yourwebsite.com"
page = requests.get(URL)
soup = BeautifulSoup(page.content, features='lxml')
# Find links
all_links = [link.get("href") for link in soup("a")]
# Only external links
ext_links = [link.get("href") for link in soup("a") if "http" in link.get("href")]

https://www.crummy.com/software/BeautifulSoup/bs4/doc/#calling-a-tag-is-like-calling-find-all


0

对我来说最简单的方法:

from urlextract import URLExtract
from requests import get

url = "sample.com/samplepage/"
req = requests.get(url)
text = req.text
# or if you already have the html source:
# text = "This is html for ex <a href='http://google.com/'>Google</a> <a href='http://yahoo.com/'>Yahoo</a>"
text = text.replace(' ', '').replace('=','')
extractor = URLExtract()
print(extractor.find_urls(text))


输出:

['http://google.com/', 'http://yahoo.com/']


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接