python - 使用 BeautifulSoup 更有效地抓取网页

我正在编写一个脚本来抓取维基百科页面,其中包含这些名称的名称列表。具体来说,我正在抓取一个维基百科页面,其中包含每个爵士钢琴家的姓名列表(至少根据维基百科)。我想要做的是将本页上所有钢琴家的名字附加到一个列表中。以下是维基百科页面的链接:https ://en.wikipedia.org/wiki/List_of_jazz_pianists


我设法用 Beautiful Soup v4 找到了一个解决方案,但它看起来很笨重。让我描述一下这个解决方案以及为什么我会实现它。(为了简洁起见,我不会在这篇文章中包含 HTML 文件)


import requests

import bs4


result = requests.get("https://en.wikipedia.org/wiki/List_of_jazz_pianists")

soup = bs4.BeautifulSoup(result.text, "html.parser")

bigList = soup.findAll('div', {'class' : 'div-col columns column-width'})

bigList 是每个 div class = div-col columns column-width 的列表,因为这些 div 包含艺术家的实际姓名。


artistList = []

index = 0

for nameTag in bigList[5].contents[1].contents:

    if index % 2 == 0:

        artistList.append(nameTag.contents[0].contents[0])

        

    index += 1

    

print(artistList)

这需要一些解释。如果您查看 Wikipedia 页面的 HTML 文件,将会有所帮助。bigList[5]给出 'F' 的所有姓氏,因为 F 是字母表中的第 6 个字符. bigList[5].contents给出一个包含 3 个元素的列表:一个换行转义字符、F 的整个<li>列表,最后是另一个换行转义字符. 因此访问F 的 bigList[5].contents[1]整个列表。给出每个元素的列表,以换行转义字符分隔。所以我的想法是,我将迭代此列表中的每个元素,仅采用偶数索引元素,因为奇数索引元素都是换行符转义字符。<li>bigList[5].contents[1].contents<li>nameTag.contents给出一个由两个元素组成的列表,钢琴家的超链接和姓名,以及他们的出生日期 - 死亡日期. 所以我选择该列表的第一个元素。最后,nameTag.contents[0].contents给出一个仅包含一个元素(钢琴家的名字)的列表,因此我拉出该列表的唯一元素,以便将其作为字符串而不是嵌套列表附加到artistList。


正如您所看到的,对于看起来应该更简单的事情来说,这是一个极其复杂的过程。鉴于我对 bs4 和使用 python 进行网页抓取总体来说是新手,我觉得有一个更好的解决方案。此外,我最终想从该页面上链接的每个钢琴家的页面收集数据。我的解决方案不是很稳健或高效,我知道这会给我推进这个项目带来问题。


有更好的方法来做我想做的事情吗?我真的很感谢您的帮助,对于帖子的长度以及任何其他不适当或非惯用的错误,我深表歉意 - 我是堆栈溢出的新手。


谢谢!


Cats萌萌
浏览 121回答 2
2回答

jeck猫

您的解决方案可能有点过于依赖页面的格式,尽管抓取维基百科总是很困难,因为带有数据的元素没有用标识符或类来标记它们保存的数据,所以您只能依赖于结构无论如何,表格保持不变。您找到了正确的数据,但真正使艺术家链接与众不同的是它们是元素<a>内的div-col <div>元素。BS4 的一个更简单的解决方案(考虑到您既需要艺术家姓名又需要他们页面的链接):from urllib import requestfrom bs4 import BeautifulSoupwith request.urlopen("https://en.wikipedia.org/wiki/List_of_jazz_pianists") as response:&nbsp; &nbsp; bs = BeautifulSoup(response, "html.parser")&nbsp; &nbsp; for div_col in bs.find_all('div', {'class': 'div-col'}):&nbsp; &nbsp; &nbsp; &nbsp; for artist_tag in div_col.find_all('a'):&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; print(f'{artist_tag.text}, {artist_tag.attrs["href"]}')请注意,这不使用第三方requests,而是标准urllib。结果:Irving Aaronson, /wiki/Irving_AaronsonAnders Aarum, /wiki/Anders_Aarum...Bojan Zulfikarpašić, /wiki/Bojan_Zulfikarpa%C5%A1i%C4%87Axel Zwingenberger, /wiki/Axel_Zwingenberger如果您注重效率(或更确切地说是简洁),那么这句话可能就是您喜欢的:result = [(a.text, a.attrs['href'])&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for d in bs.find_all('div', {'class': 'div-col'})&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; for a in d.find_all('a')]result将是艺术家姓名和链接的元组列表,即[('Irving Aaronson', '/wiki/Irving_Aaronson'), ('Anders Aarum', '/wiki/Anders_Aarum'), ..]

吃鸡游戏

找到后bigList,您可以使用此行替换其余行:[row['title']&nbsp;for&nbsp;row&nbsp;in&nbsp;bigList[5].find_all('a')]要理解此代码,请查看bigList[5]bigList[5].find_all('a')` 的输出,然后也尝试该行。您可以类似地使用href代替title来查找网址。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Python