使用python和BeautifulSoup从网页检索链接

Nep*_*pUS 133 python beautifulsoup hyperlink web-scraping

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

ars*_*ars 178

这是使用BeautifulSoup中的SoupStrainer类的简短片段:

import httplib2
from BeautifulSoup import BeautifulSoup, SoupStrainer

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

for link in BeautifulSoup(response, parse_only=SoupStrainer('a')):
    if link.has_attr('href'):
        print(link['href'])
Run Code Online (Sandbox Code Playgroud)

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

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

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

  • 在BeautifulSoup的3.2.1版本中没有`has_attr`.相反,我看到有一种叫做"has_key"的东西,它有效. (27认同)
  • +1,使用汤过滤器是个好主意,因为当你所有人都是链接时,它允许你绕过很多不必要的解析. (13认同)
  • 来自bs4进口BeautifulSoup.(不是来自BeautifulSoup导入BeautifulSoup ..)需要更正. (6认同)
  • 更新了 python3 和最新 bs4 的代码 - https://gist.github.com/PandaWhoCodes/7762fac08c4ed005cec82204d7abd61b (5认同)
  • 抬头:`/usr/local/lib/python2.7/site-packages/bs4/__init__.py:128:UserWarning:BeautifulSoup构造函数的"parseOnlyThese"参数已重命名为"parse_only". (4认同)
  • 更新python3 (2认同)
  • 结果:AttributeError:“Doctype”对象没有属性“has_attr” (2认同)

Mar*_*ers 63

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

from bs4 import BeautifulSoup
import urllib2

resp = urllib2.urlopen("http://www.gpsbasecamp.com/national-parks")
soup = BeautifulSoup(resp, from_encoding=resp.info().getparam('charset'))

for link in soup.find_all('a', href=True):
    print link['href']
Run Code Online (Sandbox Code Playgroud)

或Python 3版本:

from bs4 import BeautifulSoup
import urllib.request

resp = urllib.request.urlopen("http://www.gpsbasecamp.com/national-parks")
soup = BeautifulSoup(resp, from_encoding=resp.info().get_param('charset'))

for link in soup.find_all('a', href=True):
    print(link['href'])
Run Code Online (Sandbox Code Playgroud)

以及使用该requests的版本,其编写将适用于Python 2和3:

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

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, from_encoding=encoding)

for link in soup.find_all('a', href=True):
    print(link['href'])
Run Code Online (Sandbox Code Playgroud)

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()来确保这样的嵌入式编码提示可以胜过错误配置的服务器.

使用时requests,response.encoding如果响应具有text/*mimetype,则属性默认为Latin-1 ,即使未返回任何字符集.这与HTTP RFC一致,但在与HTML解析一起使用时会很痛苦,因此charset在Content-Type标头中设置no时应忽略该属性.

  • @MikeB:当我写这个答案时,如果你不这样做,BeautifulSoup 还没有发出警告。 (2认同)

aeh*_*lke 48

其他人推荐使用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
Run Code Online (Sandbox Code Playgroud)

  • 如果安装了BeautifulSoup 4将使用`lxml`作为默认解析器. (19认同)

And*_*son 27

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'
Run Code Online (Sandbox Code Playgroud)

  • 这解决了我的代码遇到的问题。谢谢你! (3认同)

Sen*_*t07 10

以下代码是使用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'))
Run Code Online (Sandbox Code Playgroud)


che*_*ard 8

在引擎盖下,BeautifulSoup现在使用lxml.请求,lxml和list comprehensions是一个杀手组合.

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]
Run Code Online (Sandbox Code Playgroud)

在列表comp中,"if'//'和'url.com'不在x中"是一种简单的方法来清理网站内部'导航网址的网址列表等.


QHa*_*arr 6

链接可以包含在各种属性中,因此您可以传递这些属性的列表以供选择

例如,使用 src 和 href 属性(这里我使用以 ^ 运算符开头的开头来指定这些属性值中的任何一个以 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)
Run Code Online (Sandbox Code Playgroud)

属性 = 值选择器

[属性^=值]

表示属性名称为 attr 的元素,其值以值作为前缀(前置)。


Ric*_*son 5

该脚本可以满足您的需求,而且还可以将相对链接解析为绝对链接。

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
Run Code Online (Sandbox Code Playgroud)


May*_*gle 5

要查找所有链接,我们将在此示例中使用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
Run Code Online (Sandbox Code Playgroud)