代码如下:
import requests
from bs4 import BeautifulSoup
import json
def download_all_htmls():
"""
下载所有列表页面的HTML,用于后续的分析
"""
htmls = [] #列表
for idx in range(34): #一共34页
url = f"http://www.crazyant.net/page/{idx+1}" #自动爬取所有页面
print("craw html:", url)
r = requests.get(url) #发送GET请求,返回的是一个包含服务器资源的Response对象
if r.status_code != 200: #状态码为200则表示服务器已成功处理了请求
raise Exception("error")
htmls.append(r.text)
return htmls
htmls = download_all_htmls()
def parse_single_html(html):
"""
解析单个HTML,得到数据
@return list({"link", "title", [label]})
"""
soup = BeautifulSoup(html, 'html.parser') #解析html字符串,html.parser表示解析用的解析器
articles = soup.find_all("article") #找到article标签,文章的标题和超链接都在article标签里面,find_all()返回的是一个列表
datas = [] #存放数据的列表
for article in articles:
# 查找超链接
title_node = (
article
.find("h2", class_="entry-title")
.find("a")
)
title = title_node.get_text() #标题
link = title_node["href"] #超链接
# 查找标签列表
tag_nodes = (
article
.find("span", class_="cat-links")
.find_all("a") #find_all()返回一个列表
)
tags = [tag_node.get_text() for tag_node in tag_nodes]
datas.append(
{"title": title, "link": link, "tags": tags} #将字典存入列表
)
return datas
all_datas = []
for html in htmls:
all_datas.extend(parse_single_html(html)) #extend() 函数用于在列表末尾一次性追加另一个序列中的多个值
with open("all_article_links.json", "w",encoding='utf-8') as f:
for data in all_datas:
f.write(json.dumps(data, ensure_ascii=False)+"\n")
BeautifulSoup
将一段文档传入BeautifulSoup 的构造方法,就能得到一个文档的对象, 可以传入一段字符串或一个文件句柄。首先,文档被转换成Unicode,并且HTML的实例都被转换成Unicode编码。然后,Beautiful Soup选择最合适的解析器来解析这段文档,如果手动指定解析器那么Beautiful Soup会选择指定的解析器来解析文档。
Python标准库中的HTML解析器:BeautifulSoup(markup, “html.parser”):
lxml HTML 解析器:BeautifulSoup(markup, “lxml”) pycharm中先安装wheel库,再安装lxml库
lxml XML 解析器:BeautifulSoup(markup, [“lxml-xml”])
BeautifulSoup(markup, “xml”)
html5lib解析器:BeautifulSoup(markup, “html5lib”) html5lib的解析方式与浏览器相同,生成HTML5格式的文档
输出解析后的文档:
from bs4 import BeautifulSoup
doc = "<html><h1>Heading</h1><p>Text"
soup = BeautifulSoup(doc,'lxml')
print(str(soup)) #使用 str函数将Beautiful Soup文档(或者它的子集)转换为字符串
print(soup.prettify()) #prettify()函数添加了一些换行和空格以便让文档结构看起来更清晰
print(unicode(soup)) #使用unicode()函数以Unicode字符串形式输出,Python 3不能使用unicode()函数
BeautifulSoup能够将复杂的HTML转换成为一个复杂的树形结构,其中每个节点都是python对象,所有这些对象可以分类4大类,分别为:
Tag
NavigableString
BeautifulSoup
Comment
Tag
soup = BeautifulSoup('<b class="boldest">Extremely bold</b>')
tag = soup.b
tag中最重要的属性: name和attributes
Name:
tag.name:获取tag名字
Attributes:
tag[‘属性名’]:查看特定属性,如tag[‘class’],tag[‘id’],soup.p[‘class’]
tag.attrs:查看所有属性
在Beautiful Soup中多值属性的返回类型是list
查找标签的方法:
- BeautifulSoup对象.标签名:查看标签内容,如soup.body.b。通过点取属性的方式只能获得当前位置下的第一个标签
- find() 和 find_all()
find_all()和 find()仅对Tag对象以及 顶层剖析对象有效
soup.find_all(“title”)
soup.find_all(“p”, “title”)
soup.find_all(id=“link2”)
soup.findAll(align=[“center”, “blah”])
soup.find_all(“a”, class_=“sister”)
soup.find(string=re.compile(“sisters”)) 通过 string 参数可以搜索文档中的字符串内容
soup.find_all(href=re.compile(“elsie”), id=‘link1’) 搜索每个tag的”href”属性
data_soup.find_all(attrs={“data-foo”: “value”})
tag的其它属性:
- tag.contentscontents :将tag的子节点以列表的方式输出
- tag.children :输出为生成器,可以对tag的子节点进行循环
- tag.descendants:可以对所有tag的子孙节点进行递归循环
- tag.string :如果tag只有一个 NavigableString 类型子节点,那么这个tag可以使用 .string 得到子节点
- tag .strings :如果tag中包含多个字符串,可以使用 .strings 来循环获取
- tag …stripped_strings :去除输出的字符串中多余空白内容
- tag…parent :获取某个元素的父节点
- tag.parents:可以递归得到元素的所有父辈节点
- tag.next_sibling :查询下兄弟节点
- tag.previous_sibling :查询上兄弟节点
- tag…next_element:指向解析过程中下一个被解析的对象(字符串或tag)
- tag…previous_element :指向当前被解析的对象的前一个解析对象
NavigableString
Beautiful Soup用 NavigableString 类来包装tag中的字符串,字符串不支持 .contents 或 .string 属性或 find() 方法.
如果一个标签只有一个子节点且是字符串类型,可以这样访问 tag.string,等同于tag.contents[0]的形式。
soup = BeautifulSoup('<b class="boldest">Extremely bold</b>')
print(soup.b.string)
print(soup.b.contents[0])
print(type(soup.b.string))
print(type(soup.b.contents[0]))
结果:
Extremely bold
Extremely bold
<class ‘bs4.element.NavigableString’>
<class ‘bs4.element.NavigableString’>
tag中包含的字符串不能编辑,但是可以被替换成其它的字符串,用 replace_with() 方法:
tag.string.replace_with("No longer bold")
BeautifulSoup
BeautifulSoup 对象表示的是一个文档的全部内容,包含了一个值为 “[document]” 的特殊属性 .name
soup.name
Comment
Comment 对象是一个特殊类型的 NavigableString 对象,它是文档的注释部分。
参考文献:
【1】https://www.crummy.com/software/BeautifulSoup/bs3/documentation.zh.html#Navigating%20the%20Parse%20Tree
【2】https://beautifulsoup.readthedocs.io/zh_CN/latest/#tag