使用 python 和 BeautifulSoup 从网页检索链接[关闭]

2024-12-02 08:41:00
admin
原创
170
摘要:问题描述:如何使用 Python 检索网页链接并复制链接的 URL 地址?解决方案 1:以下是使用 BeautifulSoup 中 SoupStrainer 类的简短代码片段:import httplib2 from bs4 import BeautifulSoup, SoupStrainer http =...

问题描述:

如何使用 Python 检索网页链接并复制链接的 URL 地址?


解决方案 1:

以下是使用 BeautifulSoup 中 SoupStrainer 类的简短代码片段:

import httplib2
from bs4 import BeautifulSoup, SoupStrainer

http = httplib2.Http()
status, response = http.request('http://www.nytimes.com')

for link in BeautifulSoup(response, 'html.parser', parse_only=SoupStrainer('a')):
    if link.has_attr('href'):
        print(link['href'])

BeautifulSoup 文档实际上非常好,涵盖了许多典型场景:

BeautifulSoup 文档

编辑:请注意,我使用了 SoupStrainer 类,因为如果您提前知道要解析的内容,它会更高效(内存和速度方面)。

解决方案 2:

为了完整起见,BeautifulSoup 4 版本也使用了服务器提供的编码:

from bs4 import BeautifulSoup
import urllib.request

parser = 'html.parser'  # or 'lxml' (preferred) or 'html5lib', if installed
resp = urllib.request.urlopen("http://www.gpsbasecamp.com/national-parks")
soup = BeautifulSoup(resp, parser, from_encoding=resp.info().get_param('charset'))

for link in soup.find_all('a', href=True):
    print(link['href'])

或 Python 2 版本:

from bs4 import BeautifulSoup
import urllib2

parser = 'html.parser'  # or 'lxml' (preferred) or 'html5lib', if installed
resp = urllib2.urlopen("http://www.gpsbasecamp.com/national-parks")
soup = BeautifulSoup(resp, parser, from_encoding=resp.info().getparam('charset'))

for link in soup.find_all('a', href=True):
    print link['href']

requests以及使用库的版本,其编写版本可在 Python 2 和 3 中运行:

from bs4 import BeautifulSoup
from bs4.dammit import EncodingDetector
import requests

parser = 'html.parser'  # or 'lxml' (preferred) or 'html5lib', if installed
resp = requests.get("http://www.gpsbasecamp.com/national-parks")
http_encoding = resp.encoding if 'charset' in resp.headers.get('content-type', '').lower() else None
html_encoding = EncodingDetector.find_declared_encoding(resp.content, is_html=True)
encoding = html_encoding or http_encoding
soup = BeautifulSoup(resp.content, parser, from_encoding=encoding)

for link in soup.find_all('a', href=True):
    print(link['href'])

soup.find_all('a', href=True)调用将查找所有<a>具有href属性的元素;没有属性的元素将被跳过。

BeautifulSoup 3 于 2012 年 3 月停止开发;新项目确实应该一直使用 BeautifulSoup 4。

请注意,您应该将 HTML 从字节解码的工作留给BeautifulSoup。您可以告知 BeautifulSoup 在 HTTP 响应标头中找到的字符集以协助解码,但这可能是错误的,并且与<meta>HTML 本身中找到的标头信息相冲突,这就是为什么上面使用 BeautifulSoup 内部类方法EncodingDetector.find_declared_encoding()来确保这种嵌入的编码提示能够胜过配置错误的服务器。

使用 时requestsresponse.encoding如果响应具有text/*mimetype,则该属性默认为 Latin-1,即使未返回字符集。这与 HTTP RFC 一致,但在用于 HTML 解析时会很麻烦,因此当charsetContent-Type 标头中未设置时,您应该忽略该属性。

解决方案 3:

其他人推荐使用 BeautifulSoup,但使用lxml更好。尽管它的名字如此,但它也用于解析和抓取 HTML。它比 BeautifulSoup 快得多,甚至比 BeautifulSoup 更好地处理“损坏的”HTML(他们声名鹊起)。如果您不想学习 lxml API,它还具有 BeautifulSoup 的兼容 API。

Ian Blicking 表示同意。

没有理由再使用 BeautifulSoup,除非你使用 Google App Engine 或者其他不允许使用纯 Python 的东西。

lxml.html 也支持 CSS3 选择器,所以这种事情很简单。

使用 lxml 和 xpath 的示例如下所示:

import urllib
import lxml.html
connection = urllib.urlopen('http://www.nytimes.com')

dom =  lxml.html.fromstring(connection.read())

for link in dom.xpath('//a/@href'): # select the url in href for all a tags(links)
    print link

解决方案 4:

import urllib2
import BeautifulSoup

request = urllib2.Request("http://www.gpsbasecamp.com/national-parks")
response = urllib2.urlopen(request)
soup = BeautifulSoup.BeautifulSoup(response)
for a in soup.findAll('a'):
  if 'national-park' in a['href']:
    print 'found a url with national-park in the link'

解决方案 5:

以下代码使用urllib2和检索网页中可用的所有链接BeautifulSoup4

import urllib2
from bs4 import BeautifulSoup

url = urllib2.urlopen("http://www.espncricinfo.com/").read()
soup = BeautifulSoup(url)

for line in soup.find_all('a'):
    print(line.get('href'))

解决方案 6:

链接可以包含多种属性,因此您可以将这些属性的列表传递给select

例如,具有srchref属性(这里我使用以 ^ 运算符开头来指定这些属性值中的任何一个都以 http 开头):

from bs4 import BeautifulSoup as bs
import requests
r = requests.get('https://stackoverflow.com/')
soup = bs(r.content, 'lxml')
links = [item['href'] if item.get('href') is not None else item['src'] for item in soup.select('[href^="http"], [src^="http"]') ]
print(links)

属性 = 值选择器

[属性^=值]

表示具有属性名称 attr 的元素,该属性的值以 value 为前缀(前面)。

还有常用的$(以...结尾)和*(包含)运算符。有关完整语法列表,请参阅上面的链接。

解决方案 7:

BeautifulSoup 现在在底层使用 lxml。请求、lxml 和列表推导构成了一个杀手级组合。

import requests
import lxml.html

dom = lxml.html.fromstring(requests.get('http://www.nytimes.com').content)

[x for x in dom.xpath('//a/@href') if '//' in x and 'nytimes.com' not in x]

在列表计算中,“如果‘//’和‘url.com’不在x中”是一种简单的方法,用于清除站点‘内部’导航网址等的网址列表。

解决方案 8:

该脚本不仅可以完成您要找的工作,还可以将相对链接解析为绝对链接。

import urllib
import lxml.html
import urlparse

def get_dom(url):
    connection = urllib.urlopen(url)
    return lxml.html.fromstring(connection.read())

def get_links(url):
    return resolve_links((link for link in get_dom(url).xpath('//a/@href')))

def guess_root(links):
    for link in links:
        if link.startswith('http'):
            parsed_link = urlparse.urlparse(link)
            scheme = parsed_link.scheme + '://'
            netloc = parsed_link.netloc
            return scheme + netloc

def resolve_links(links):
    root = guess_root(links)
    for link in links:
        if not link.startswith('http'):
            link = urlparse.urljoin(root, link)
        yield link  

for link in get_links('http://www.google.com'):
    print link

解决方案 9:

为了查找所有链接,我们将在此示例中将 urllib2 模块与 re.module 结合使用
re 模块中最强大的函数之一是“re.findall()”。re.search() 用于查找模式的第一个匹配项,而 re.findall() 则查找所有*
匹配项并将它们作为字符串列表返回,每个字符串代表一个匹配项*

import urllib2

import re
#connect to a URL
website = urllib2.urlopen(url)

#read html code
html = website.read()

#use re.findall to get all the links
links = re.findall('"((http|ftp)s?://.*?)"', html)

print links

解决方案 10:

只是为了获取链接,不需要 B.soup 和正则表达式:

import urllib2
url="http://www.somewhere.com"
page=urllib2.urlopen(url)
data=page.read().split("</a>")
tag="<a href=\""
endtag="\">"
for item in data:
    if "<a href" in item:
        try:
            ind = item.index(tag)
            item=item[ind+len(tag):]
            end=item.index(endtag)
        except: pass
        else:
            print item[:end]

对于更复杂的操作,当然还是BSoup为佳。

解决方案 11:

为什么不使用正则表达式:

import urllib2
import re
url = "http://www.somewhere.com"
page = urllib2.urlopen(url)
page = page.read()
links = re.findall(r"<a.*?s*href=\"(.*?)\".*?>(.*?)</a>", page)
for link in links:
    print('href: %s, HTML text: %s' % (link[0], link[1]))

解决方案 12:

BeautifulSoup4下面是使用@ars 接受的答案和、requestswget模块来处理下载的示例。

import requests
import wget
import os

from bs4 import BeautifulSoup, SoupStrainer

url = 'https://archive.ics.uci.edu/ml/machine-learning-databases/eeg-mld/eeg_full/'
file_type = '.tar.gz'

response = requests.get(url)

for link in BeautifulSoup(response.content, 'html.parser', parse_only=SoupStrainer('a')):
    if link.has_attr('href'):
        if file_type in link['href']:
            full_path = url + link['href']
            wget.download(full_path)

解决方案 13:

经过以下修正(涵盖无法正常工作的情况),我发现@Blairg23 的答案有效:

for link in BeautifulSoup(response.content, 'html.parser', parse_only=SoupStrainer('a')):
    if link.has_attr('href'):
        if file_type in link['href']:
            full_path =urlparse.urljoin(url , link['href']) #module urlparse need to be imported
            wget.download(full_path)

对于 Python 3:

urllib.parse.urljoin必须使用才能获得完整的 URL。

解决方案 14:

BeatifulSoup 自己的解析器可能很慢。使用lxml可能更可行,因为它能够直接从 URL 进行解析(下面会提到一些限制)。

import lxml.html

doc = lxml.html.parse(url)

links = doc.xpath('//a[@href]')

for link in links:
    print link.attrib['href']

上面的代码将按原样返回链接,在大多数情况下,它们将是相对链接或来自站点根目录的绝对链接。由于我的用例是仅提取特定类型的链接,因此下面是一个将链接转换为完整 URL 的版本,并且可选地接受像 这样的 glob 模式*.mp3。但它不会处理相对路径中的单点和双点,但到目前为止我不需要它。如果您需要解析包含../或 的URL 片段,./那么urlparse.urljoin可能会派上用场。

注意:直接 lxml url 解析不处理加载https并且不执行重定向,因此下面的版本使用urllib2+ lxml

#!/usr/bin/env python
import sys
import urllib2
import urlparse
import lxml.html
import fnmatch

try:
    import urltools as urltools
except ImportError:
    sys.stderr.write('To normalize URLs run: `pip install urltools --user`')
    urltools = None


def get_host(url):
    p = urlparse.urlparse(url)
    return "{}://{}".format(p.scheme, p.netloc)


if __name__ == '__main__':
    url = sys.argv[1]
    host = get_host(url)
    glob_patt = len(sys.argv) > 2 and sys.argv[2] or '*'

    doc = lxml.html.parse(urllib2.urlopen(url))
    links = doc.xpath('//a[@href]')

    for link in links:
        href = link.attrib['href']

        if fnmatch.fnmatch(href, glob_patt):

            if not href.startswith(('http://', 'https://' 'ftp://')):

                if href.startswith('/'):
                    href = host + href
                else:
                    parent_url = url.rsplit('/', 1)[0]
                    href = urlparse.urljoin(parent_url, href)

                    if urltools:
                        href = urltools.normalize(href)

            print href

使用方法如下:

getlinks.py http://stackoverflow.com/a/37758066/191246
getlinks.py http://stackoverflow.com/a/37758066/191246 "*users*"
getlinks.py http://fakedomain.mu/somepage.html "*.mp3"

解决方案 15:

外部和内部链接都可能存在许多重复链接。要区分两者并使用集合获取唯一链接,请执行以下操作:

# Python 3.
import urllib    
from bs4 import BeautifulSoup

url = "http://www.espncricinfo.com/"
resp = urllib.request.urlopen(url)
# Get server encoding per recommendation of Martijn Pieters.
soup = BeautifulSoup(resp, from_encoding=resp.info().get_param('charset'))  
external_links = set()
internal_links = set()
for line in soup.find_all('a'):
    link = line.get('href')
    if not link:
        continue
    if link.startswith('http'):
        external_links.add(link)
    else:
        internal_links.add(link)

# Depending on usage, full internal links may be preferred.
full_internal_links = {
    urllib.parse.urljoin(url, internal_link) 
    for internal_link in internal_links
}

# Print all unique external and full internal links.
for link in external_links.union(full_internal_links):
    print(link)

解决方案 16:

import urllib2
from bs4 import BeautifulSoup
a=urllib2.urlopen('http://dir.yahoo.com')
code=a.read()
soup=BeautifulSoup(code)
links=soup.findAll("a")
#To get href part alone
print links[0].attrs['href']
相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1565  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1354  
  信创国产芯片作为信息技术创新的核心领域,对于推动国家自主可控生态建设具有至关重要的意义。在全球科技竞争日益激烈的背景下,实现信息技术的自主可控,摆脱对国外技术的依赖,已成为保障国家信息安全和产业可持续发展的关键。国产芯片作为信创产业的基石,其发展水平直接影响着整个信创生态的构建与完善。通过不断提升国产芯片的技术实力、产...
国产信创系统   21  
  信创生态建设旨在实现信息技术领域的自主创新和安全可控,涵盖了从硬件到软件的全产业链。随着数字化转型的加速,信创生态建设的重要性日益凸显,它不仅关乎国家的信息安全,更是推动产业升级和经济高质量发展的关键力量。然而,在推进信创生态建设的过程中,面临着诸多复杂且严峻的挑战,需要深入剖析并寻找切实可行的解决方案。技术创新难题技...
信创操作系统   27  
  信创产业作为国家信息技术创新发展的重要领域,对于保障国家信息安全、推动产业升级具有关键意义。而国产芯片作为信创产业的核心基石,其研发进展备受关注。在信创国产芯片的研发征程中,面临着诸多复杂且艰巨的难点,这些难点犹如一道道关卡,阻碍着国产芯片的快速发展。然而,科研人员和相关企业并未退缩,积极探索并提出了一系列切实可行的解...
国产化替代产品目录   28  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用