介绍
HTML代码如下:
<ul class="sf-r-list">
<li>
<a href="/book/77" class="sc-list-cover fl">
<img class="ba_page_prvimg" onload="baImgCenter(this)" badt_outwidth="" src="/cover/0/0/77/!m">
</a>
<div class="sf-r-info">
<h3 class="sf-r-infotit"><a href="/book/77" class="ellipsis-2">Android多媒体开发高级编程——为智能手机和平板电脑开发图形、音乐、视频和富媒体应用</a>
</h3>
<p class="sf-r-infoau text-truncate"> (美) 艾佛瑞 (Every,.)...</p>
<p class="sf-r-infotext ellipsis-2">《Android多媒体开发高级编程》使用清晰、直观的示例介绍了Android SDK中丰富的多媒体功能,有助于您开发能够创建、播放和共享多媒体的优秀Android应用程序。许多Android设备本身就是照相机、相册、...</p>
<div class="sf-r-infoprice">
<span style="color:#8E9AA6;"> 暂不销售</span>
</div>
</div>
</li>
...<!-- 与前述<li> .. </li>类同 -->
...
<li style="float:none;margin:0;display:block;clear:both;"></li>
</ul>
需要把<ul> ...</ul
直接的列表项中的信息抓取出来,其中每个列表项包含书籍的名称、作者、简介和价格信息。我最初使用的代码如下:
from bs4 import BeautifulSoup
from urllib.request import urlopen
html = urlopen('/category/tid_2004/pid_/pn_1014.html')
bs = BeautifulSoup(html,'lxml')
book_ul = bs.find("ul",class_="sf-r-list")
book_lis = book_ul.find_all("li")
for item in book_lis:
print(item.prettify())
但是抓取的列表项中总会包含:
<li style="float:none;margin:0;display:block;clear:both;"></li>
当时在BeautifulSoup的函数find_all()中的参数上想了一些办法,因为我预感对标签的筛选肯定在参数中有所体现。可是都不成功。在我读到的爬虫书籍中,对此场景的技术方案都没讲解。无奈最后我采用了笨方法将<li style="float:none;margin:0;display:block;clear:both;"></li>
剔除出去,代码如下:
from bs4 import BeautifulSoup
from urllib.request import urlopen
html = urlopen('/category/tid_2004/pid_/pn_1014.html')
bs = BeautifulSoup(html,'lxml')
book_ul = bs.find("ul",class_="sf-r-list")
book_lis = book_ul.find_all("li")
for item in book_lis:
if book_li.find("a"):
print(item.prettify())
亦即,我是通过判断在标签<li></li>
是否包含子标签<a></a>
来完成的。当时也顺利完成了爬虫的功能。但这个问题在我脑中记录下来了。直到今天,读书籍《Web Scraping with Python》第二版1的85页代码时,发现:
downloadList = bs.findAll(src=True)
受启发,可以用到本文场景中。当时书上也没讲解src=True
的含义。
优雅的解决方案
在BeautifulSoup的函数find_all()中的参数中设置某个属性值为False
或True
,允许我们在匹配时控制某个属性在标签中是否出现,以此来匹配查找。于是,本应用场景的优美解决方案为:
#
# 2020-08-20
from bs4 import BeautifulSoup
from urllib.request import urlopen
html = urlopen('/category/tid_2004/pid_/pn_1014.html')
bs = BeautifulSoup(html,'lxml')
book_ul = bs.find("ul",class_="sf-r-list")
#book_lis = book_ul.find_all("li")
book_lis = book_ul.find_all("li",style=False)
for item in book_lis:
print(item.prettify())
-
Ryan Mitchell. Web Scraping with Python: Collecting more data from the Modern Web. 2ed, O’Reilly, 2018. ↩︎