BeautifulSoup实现网页导航

8

我对如何使用BeautifulSoup来遍历HTML树有些困惑。

import requests
from bs4 import BeautifulSoup

url = 'http://examplewebsite.com'
source = requests.get(url)
content = source.content
soup = BeautifulSoup(source.content, "html.parser")

# Now I navigate the soup
for a in soup.findAll('a'):
    print a.get("href")
  1. 是否有一种方法可以通过标签找到特定的href?例如,在在线目录中,我想要的所有href都被称为某个名称,例如price

  2. 我想要的href链接都在网页的特定位置内,即页面的 <body> 和特定<div>之内。我可以只访问这些链接吗?

  3. 如何爬取每个href链接中的内容并保存到文件中?


(2)你说的“特定位置”是什么意思?你能给出源文件的摘录吗?是指在一个<h1>标签附近还是其他什么地方? (3)你所说的链接的“内容”是什么意思?你想要下载链接另一端的文件吗? - RobertB
@RobertB(2)是的,我的意思是在某个<table>中有许多href (3)您单击链接,直到到达数据表。我想抓取这些数据。 - ShanZhengYang
1个回答

11

使用BeautifulSoup,这些都是可行且简单的。

(1) 有没有一种方法可以通过标签仅查找特定的href?例如,在在线目录中,我想要的所有href都被称为某个名称,例如价格。

假设您需要的所有链接在文本中都包含price - 您可以使用text参数:

soup.find_all("a", text="price")  # text equals to 'price' exactly
soup.find_all("a", text=lambda text: text and "price" in text)  # 'price' is inside the text

是的,您可以使用functions和许多其他不同类型的对象来过滤元素,例如编译好的正则表达式

import re

soup.find_all("a", text=re.compile(r"^[pP]rice"))

如果price在“href”属性中,您可以使用以下CSS选择器
soup.select("a[href*=price]")  # href contains 'price'
soup.select("a[href^=price]")  # href starts with 'price'
soup.select("a[href$=price]")  # href ends with 'price'

或者,通过find_all()
soup.find_all("a", href=lambda href: href and "price" in href)

「(2) 我想获取的 href 链接都在网页的某个位置,且位于特定的 {容器} 中。我能否只访问这些链接?」
可以的,找到相应的容器,然后调用 find_all() 或其他搜索方法 即可:
container = soup.find("div", class_="container")
for link in container.select("a[href*=price"):
    print(link["href"])

或者,您可以按照搜索具有所需属性或属性值的特定元素内部链接的方式编写CSS选择器。例如,在此处,我们正在搜索位于具有“container”类的
元素内部的具有href属性的元素:
soup.select("div.container a[href]")

如果我理解正确,您需要获取适当的链接,跟随它们并将页面的源代码保存到本地HTML文件中。根据您的要求,有多种选择(例如,速度可能很关键。或者,这只是一项一次性任务,您不关心性能)。如果您仍然使用requests,则代码的性质将是阻塞的-您将提取链接,跟随它,保存页面源代码,然后继续下一个-主要缺点是它会很慢(取决于首先有多少链接)。以下是可供参考的示例代码:
from urlparse import urljoin

from bs4 import BeautifulSoup
import requests

base_url = 'http://examplewebsite.com'
with requests.Session() as session:  # maintaining a web-scraping session
    soup = BeautifulSoup(session.get(base_url).content, "html.parser")

    for link in soup.select("div.container a[href]"):
        full_link = urljoin(base_url, link["href"])
        title = a.get_text(strip=True)

        with open(title + ".html", "w") as f:
            f.write(session.get(full_link).content)

你可以查看
grequestsScrapy 来解决这部分问题。

@alexce "跟随它们并将页面的源代码保存到本地HTML文件中。" 实际上,我需要将每个单独页面的源代码保存到一个HTML文件中。因此,可以将其视为跨多个网页的巨大HTML树;我需要一直跟随链接/子级到达树的最底部,保存这些数据,追加到我的文件中,然后继续进行。 - ShanZhengYang
@ShanZhengYang 看起来你需要以“追加”模式打开同一个HTML文件,或者只需打开一次以进行写操作,并在跟随链接和下载页面时保持它处于打开状态。谢谢。 - alecxe

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