目录
bs4 是 html 里通过标签名和属性定位数据内容,以达到解析数据的目的
一、分析网页:
本次抓取当当网近一月图书畅销排行榜书名,定位到所需要的用到的标签
这个网页发起 get 请求,返回 text 类型的网页源码
抓取思路:
1.拿到源代码
2.使用 bs4 进行数据解析,拿到想要的结果
二、爬取
(一)发起请求+获得网页源码
本次实例重在体会 BS4 数据解析方法,所以把两步放在一起了
# 指定URL
url = 'http://bang.dangdang.com/books/bestsellers/01.00.00.00.00.00-recent30-0-0-1-1'
# UA伪装
head = {'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36'}
# 获得响应数据
response = requests.get(url, headers=head).text
(二)解析数据
1.实例化
bs4 是把页面源代码交给 beautifulsoup 处理,生成bs对象(理解为实例化一个 beautifulsoup 类)
soup = BeautifulSoup(response, "html.parser")
print(type(soup))
# 指定 html 解析器,否则Python会有警告,不知道用哪种解析器
<class 'bs4.BeautifulSoup'>
2.通过标签抓取
从 bs 对象中查找数据,有find(标签,属性1=值1)和find_all(标签,属性1=值1)两种方法,功能是找第一个标签/所有标签所标记的
观察标签的结构:在<ul class="bang_list clearfix bang_list_mode">→<li class>→<div class="name">→<a href="xxx">
现在我知道每个<li>标签对应着一本书,里面<div>对应不同信息,如名称价格等,我们需要的书名就放在<div class=“name”>下的超链接标签<a href="xxx">中
定位到 ul:
html_1 = soup.find("ul", attrs={'class': "bang_list clearfix bang_list_mode"})
定位到 li:
html_2 = html_1.find_all("li")
我们需要遍历当下每个 li 标签,然后获得书名
top=1
# 遍历网页源码的列表
for i in range(20):
# 将li中name类型的div标签赋给book_name_lable
book_name_lable = html_2[i].find("div", class_="name")
# a标签中标记的就是书名,利用.text可以拿到标签所标记的内容
book_name = book_name_lable.find("a").text
print(str(top)+book_name) #记得 str,+是不能拼接数字和字符串的
i += 1
top +=1
这样我们就能看到第一页的Top20:
1乡土中国(精装版 附赠书签)
2我与地坛(纪念版)
3红星照耀中国 青少版 八年级上册 人民文学出版社 团购电话40010...
4中国古代神话 山海经 希腊神话故事 世界经典神话与传说故事四年级...
5中国民间故事 田螺姑娘 快乐读书吧五年级上册推荐阅读(中小学生课...
6被讨厌的勇气:“自我启发之父”阿德勒的哲学课 岸见一郎
7童年 快乐读书吧六年级上指定阅读 《语文》阅读丛书 人民文学出版...
8朝花夕拾 七年级上 名著阅读课程化丛书 导读版 人民教育出版社
9长安的荔枝
10活着(余华代表作,精装,易烊千玺推荐阅读)
11童年(小学语文“快乐读书吧”・六年级上阅读,高尔基自传体三部...
12朝花夕拾(《语文》推荐阅读丛书)七年级上册推荐阅读 人民文学...
13你也走了很远的路吧(新增2万余字,4篇文章,关于特殊时期成长的...
14红楼梦原著版(上、下册,全两册,全本120回)(团购电话:400-10...
15人教版快乐读书吧阅读课程化丛书 三年级上册套装(稻草人+安徒生...
16红星照耀中国 八年级上 名著阅读课程化丛书 导读版 人民教育出版...
17蛤蟆先生去看心理医生(热销300万册!英国经典心理咨询入门书,知...
18我从未如此眷恋人间:周深“终于开始学会眷恋这人间”史铁生、季...
19小英雄雨来 童年 爱的教育 六年级上册快乐读书吧推荐阅读(中小学...
20中国古代神话 快乐读书吧四年级上册推荐阅读(中小学生课外阅读指...
Process finished with exit code 0
三、改进
我不想局限于第一页,我想看前5页的Top100畅销书书名:
点击第二页时,最后一个数字发生了变化,所以只要将最后一个数字改为动态的,即可灵活获取想要的数据了
top = 1
for p in range(5):
response = requests.get(new_url%p, headers=head).text
soup = BeautifulSoup(response, "html.parser") # 指定html解析器,Python会有警告
html_1 = soup.find("ul", attrs={'class': "bang_list clearfix bang_list_mode"})
html_2 = html_1.find_all("li")
for i in range(len(html_2)): # 遍历网页源码的列表
book_name_lable = html_2[i].find("div", class_="name")
book_name = book_name_lable.find("a").text
print(str(top) + book_name)
i += 1
top += 1
嵌套循环:每页都会发起一个请求获得数据,并实例化一个 BeautifulSoup,找到一页中所有<li> 标签之后,根据<li>标签个数进行循环(一页20个<li>标签表示20个书本,每个<li>都要定位到<a>为止才能取到名字并打印输出)
结果成功获取前1-100的书名
为了更详细了解价格与折扣,我又加了一点点细节:
for p in range(5):
response = requests.get(new_url % p, headers=head).text
soup = BeautifulSoup(response, "html.parser") # 指定html解析器,Python会有警告
html_1 = soup.find("ul", attrs={'class': "bang_list clearfix bang_list_mode"})
html_2 = html_1.find_all("li")
for i in range(len(html_2)): # 遍历网页源码的列表
book_name_lable = html_2[i].find("div", class_="name")
book_name = book_name_lable.find("a").text
price_div = html_2[i].find("div", class_="price")
price_lable = price_div.find("p")
my = price_lable.find("span", attrs={"span", "price_n"}).text
sy = price_lable.find("span", attrs={"span", "price_r"}).text
discount = price_lable.find("span", "price_s").text
print('Top' + str(
top) + ':' + book_name + ' 实洋:' + sy + ' 码洋:' + my + ' 折扣:' + discount)
i += 1
top += 1
看起来效果还行
四、错误
(一)不可连用 find_all
这是因为 find_all 得到的是结果集,不唯一,在连续使用 find_all 时会出现这个报错
(二)字符串与数字不得直接拼接
(三).find返回的结果
.find返回的结果是标签,需要再后面加上.text才可得到网页中对应标签标记的内容,如果是想拿到标签的值,用 .get 即可(如图片链接会保存在属性中)
五、代码
import requests
from bs4 import BeautifulSoup
url = 'http://bang.dangdang.com/books/bestsellers/01.00.00.00.00.00-recent30-0-0-1-1'
new_url = 'http://bang.dangdang.com/books/bestsellers/01.00.00.00.00.00-recent30-0-0-1-%d'
head = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36'}
response = requests.get(url, headers=head).text
soup = BeautifulSoup(response, "html.parser") # 指定html解析器,Python会有警告
top = 1
for p in range(5):
response = requests.get(new_url % p, headers=head).text
soup = BeautifulSoup(response, "html.parser") # 指定html解析器,Python会有警告
html_1 = soup.find("ul", attrs={'class': "bang_list clearfix bang_list_mode"})
html_2 = html_1.find_all("li")
for i in range(len(html_2)): # 遍历网页源码的列表
book_name_lable = html_2[i].find("div", class_="name")
book_name = book_name_lable.find("a").text
price_div = html_2[i].find("div", class_="price")
price_lable = price_div.find("p")
my = price_lable.find("span", attrs={"span", "price_n"}).text
sy = price_lable.find("span", attrs={"span", "price_r"}).text
discount = price_lable.find("span", attrs={"span", "price_s"}).text
print('Top' + str(
top) + ':' + book_name + ' 实洋:' + sy + ' 码洋:' + my + ' 折扣:' + discount)
i += 1
top += 1