开往未来的列车|Python爬虫快速入门,静态网页爬取( 三 )


2.2 Tag对象BeautifulSoup将HTML中的元素封装成了Tag对象 。 和BeautifulSoup对象一样 , Tag对象里也有find()和find_all()方法 。 因此 , 我们可以不断地调用这两个方法 , 一层一层地找到我们需要的数据 。 依然使用之前的例子:
登录/注册豆瓣读书 Top 250豆瓣书店红楼梦百年孤独白夜行我们可以看到 , 书名在a标签中 。 但如果直接使用soup.find_all(‘a’)的话 , 第二行的“登录/注册”和第五行的“豆瓣书店”也会被获取到 , 因此我们需要将这些无效数据过滤掉 。
深入思考一下不难发现 , 书名在class="item"的div标签里的a标签内 。 我们只要先找到所有class="item"的div标签 , 然后再找到其中的a标签即可 , 因此我们可以像下面这样来获取书名的数据:
items = soup.find_all('div', class_='item')for item in items: print(item.find('a'))输出结果:
红楼梦百年孤独白夜行这样 , 我们就找到了所有书名的数据 。 但此时返回的还是Tag对象 。 如果我们只想要书名和对应的链接呢?这就用到了Tag对象的text属性和HTML属性名取值 。
items = soup.find_all('div', class_='item')for item in items:tag = item.find('a')name = tag.textlink = tag['href']print(name, link)输出结果:
红楼梦 百年孤独 白夜行 我们通过Tag对象的text属性拿到了a标签里的文字内容 , 即红楼梦等 。 然后我们通过和字典取值一样的方式 , 将HTML属性名作为键 , 得到了对应属性的值 。 这里是以href属性为例 , 其他的HTML属性也同样可以 。
Tag对象的常用属性和方法总结如下:
属性/方法作用tag.find()返回符合条件的首个数据tag.find_all()返回符合条件的所有数据tag.text获取标签的文本内容tag[‘属性名’]获取标签属性的值
我们通过多次调用find()或find_all()方法一层层地找到了我们需要的数据 。 那有没有什么方法可以直接就找到我们需要的数据 , 而不用多次查找吗?
答案是肯定的 , 这就需要用到CSS选择器了 。
2.3 CSS选择器在CSS选择器中 , #代表id , .代表class 。 比如:#a表示id=‘a’的所有元素 , .b表示class=‘b’的所有元素 。 当然 , 我们也可以直接通过标签名选择对应的元素 , 例如:a表示所有的a元素 。
事实上 , 它们还可以组合在一起 , 选择同时符合条件的元素 , 比如:a#b表示所有id=‘b’的a元素 , d.c 表示所有class=‘c’的d元素 , #b.c 表示所有 id=‘b’ 且 class=‘c’ 的元素 , .c.f 表示所有class同时为c和f的元素 。
需要注意的是 , 选择同时符合条件的元素 , 选择器之间不能有空格 , 如果写成.c .f就是另一个意思了 。 这是因为 , 当两个选择器之间加了空格 , 表示子元素选择 。 还是以.c .f为例 , 它表示选择所有class=‘c’的元素里面class=‘f’的元素 , 即嵌套在class=‘c’的元素里面class=‘f’的元素 。 这个嵌套可以是任意层级的 , 只要在里面就行 , 不要求直接嵌套在第一层 。 如果只需要直接嵌套在第一层符合条件的元素 , 可以用>分隔 , 例如:.c > .f 。
我们来通过一个例子了解一下CSS选择器的用法:
from bs4 import BeautifulSouphtml = '''红楼梦
白夜行
'''soup = BeautifulSoup(html, 'html.parser')print(soup.select('.item.book'))print(soup.select('.item .book'))print(soup.select('.item > .book'))
输出结果:
[][红楼梦
,白夜行
][红楼梦
]
BeautifulSoup对象有一个select()方法 , 我们将CSS 选择器传进去即可直接找到我们需要的元素 。 之前查找在class="item"的div标签里的a标签的代码就可以这样写: