bs4主要知识点介绍及实例讲解
bs4 是第三方解析html数据的包
from bs4 import BeautifulSoup
lxml 解析读取html的第三方解释器,解析速度快,底层通过c实现
# 1.网页源代码 2.解析器名称
bs = BeautifulSoup(html, 'lxml')
# bs 是BeautifulSoup 的一个对象
获取某个节点
# bs4.element.Tag 每一个节点都是一个Tag类的对象
# bs.title.name 获取的是标签的名称
# bs.title.text 获取标签之间的文本内容
# 获取某个标签的属性
# attrs 获取标签节点的所有属性和值,是一个字典
print(bs.a.attrs['href'])
# 如果一个属性有多个值,该属性值为一个列表
print(bs.a.attrs['class'])
# bs4.element.NavigableString 标签节点之间的text文本
# bs 是将html代码转换为一个Python对象
# Tag:指的就是HTML中的每一个完整标签节点(包含开始、结束标签)
# NavigableString 指的就是标签之间的text文本,不包含标签
contetns 获取某个节点下直接子标签,返回的是一个列表,列表中放的是Tag节点对象
print(bs.body.contents)
print(bs.head.contents)
print(bs.body.contents[1])
# 返回的是一个生成器对象
result = bs.body.children
获取所有的子孙节点,包含子节点\内容,子节点的子节点\内容...,返回生成器对象
print(list(bs.body.descendants))
查找节点的父节点
print(bs.title.parent)
# 父级的父级
print(bs.title.parent.parent)
查找兄弟节点
# 找到下一个兄弟节点
print(bs.a.next_sibling.next_sibling)
# 找上一个兄弟节点
print(bs.p.previous_sibling.previous_sibling)
搜索文档树中数据
# 1.通过标签名,查找标签
# find_all() 查找符合条件的所有标签,返回列表,列表中存放Tag对象
res = bs.find_all('p')
# 可以通过多个标签名进行查找
res = bs.find_all(['a', 'p', 'span'])
print(res)
# 2.查找具有唯一性质的标签
# 通过id查找标签节点,返回节点对象
res = bs.find(id='bottom')
print(res)
# class 在Python是一个关键字 class_代替class使用
res = bs.find_all(class_='red')
print(res)
通过css样式选择器查找标签
# select_one 返回是节点对象
res = bs.select_one('#top')
print(res)
# select() 返回一个列表,列表中存放所有找到节点对象
res = bs.select('.red')
print(res)
# 如果查找直接子标签 > 大于号两边要有空格
# ValueError: Unsupported or invalid CSS selector: "p>span"
res = bs.select('p > span')
print(res)
res = bs.select('#bottom a')
print(res)
# 找到整个网页中使用新开窗口打开链接的a标签
links = bs.select('a[target="_blank"]')
print(links)
实例
利用bs4爬取伯乐在线(分别存储在数据库和xls表中)
# -*- coding: utf-8 -*-
__author__ = '木之易'
__date__ = '2018/8/14 15:56'
from bs4 import BeautifulSoup
import requests
import sqlite3
import xlwt
class BoleSpider(object):
def __init__(self):
self.url = 'http://blog.jobbole.com/'
self.a_href = ''
self.html = ''
self.retry = 0
self.count = 0
self.save_count = 0
self.headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:61.0) Gecko/20100101 Firefox/61.0'}
self.conn = None
self.cursor = None
self.creat_excel()
self.create_table()
def creat_excel(self):
"""创建表"""
# 创建工作簿对象,指定编码格式
self.workbook = xlwt.Workbook(encoding='utf-8')
# 添加一张数据表,用来存取爬到的信息
self.sheet = self.workbook.add_sheet('bole_data')
# 向表中添加数据
# 1. 行号 2. 列号 3. 写入的数据
# 添加表头
self.sheet.write(0, 0, '文章标题')
self.sheet.write(0, 1, '时间')
self.sheet.write(0, 2, '出处')
self.sheet.write(0, 3, '封面图地址')
self.sheet.write(0, 4, '内容')
def connect_sql(self):
"""连接数据库,获取游标"""
self.conn = sqlite3.connect('bole.db')
self.cursor = self.conn.cursor()
def close_sql(self):
"""关闭数据库"""
# 提交操作
self.conn.commit()
# 关闭游标
self.cursor.close()
# 关闭数据库
self.conn.close()
def create_table(self):
# 连接数据库
self.connect_sql()
# 准备sql语句
sql = 'CREATE TABLE IF NOT EXISTS bole(id INTEGER PRIMARY KEY, title CHAR, time CHAR, author CHAR, http CHAR, content CHAR )'
# 执行sql
self.cursor.execute(sql)
# 关闭sql
self.close_sql()
def save_data(self, *args):
"""保存数据"""
self.save_count += 1
# *args 将元组看做一个容器,进行枚举
for idx, data in enumerate(args):
# 写入数据
self.sheet.write(self.save_count, idx, data)
self.workbook.save('bole数据.xls')
# 连接数据库
self.connect_sql()
# 准备sql语句
sql = "INSERT INTO bole(title, time, author, http, content)VALUES('%s','%s','%s','%s','%s')" % args
# 执行sql
self.cursor.execute(sql)
# 关闭sql
self.close_sql()
def get_html(self, url):
"""可以重试三次"""
try:
self.retry += 1
response = requests.get(url=url, headers=self.headers)
self.html = response.text
except Exception as e:
if self.retry > 3:
return
self.get_html(url)
def parse_index(self):
"""解析主页下的分类地址"""
bs = BeautifulSoup(self.html, 'lxml')
# print(bs)
results = bs.select('#main-nav div li a')
# print(results)
# 爬取指定分类(指定分类下的地址)
self.a_href = results[1].attrs['href']
# print(self.a_href)
# print(111)
def page_index(self):
"""获取分页下的分页地址"""
self.get_html(self.a_href)
# 获取分页下的分页地址(每篇文章的地址)
bs = BeautifulSoup(self.html, 'lxml')
res = bs.select('.post-meta .archive-title')
# 爬取所有文章
count = 0
for a in res:
count += 1
print('正在爬取第%s篇' % count)
hr = a.attrs['href']
self.get_html(hr)
self.parse_list()
# # 爬取指定分类
# hr = res[4].attrs['href']
# self.get_html(hr)
# self.parse_list()
def next_page(self):
"""获取下一页"""
self.get_html(self.a_href)
bs = BeautifulSoup(self.html, 'lxml')
res = bs.select('.next')
for r in res:
if '下一页' in r.text:
self.a_href = r.attrs['href']
else:
print('信息爬取完毕')
return None
def parse_list(self):
"""解析列表页,提取详情链接"""
bs = BeautifulSoup(self.html, 'lxml')
# 得到第一个关键词字符串
title = bs.select_one('.entry-header h1').text
print('正在爬取 %s ,请稍后' % title)
# 得到第二个关键词字列表
res = bs.select_one('.entry-meta-hide-on-mobile').text.split()
# print(res)
# 转换成一个字符串
# 使用列表生成式把列表中的单个元素全部转化为str类型并用.join把列表中的元素聚合成字符串
time = ''.join([str(i) for i in res])
# print(time)
# 得到第三个关键词字符串
author = bs.select_one('.copyright-area').text
# print(author)
# 得到图片网址
http = ''
res = bs.select('.aligncenter')
for a in res:
try:
h = a.attrs['src']
http += h + ' '
except Exception as e:
pass
# print(http)
content = ''
# 获取文章主题内容
res = bs.select('.entry p')
for i in res:
# con = i.text.replace(' ', '')
con = i.text.replace("'", "‘")
content += con
# print(content)
self.save_data(title, time, author, http, content)
def run(self):
print('启动爬虫')
self.get_html(url=self.url)
self.parse_index()
self.get_html(self.a_href)
self.page_index()
num = 1
while True:
num += 1
print('正在爬取第 %s 页数据,请稍后' % num)
# 获取下一页地址
self.next_page()
if self.a_href:
self.get_html(self.a_href)
self.page_index()
else:
break
if __name__ == '__main__':
bole = BoleSpider()
bole.run()
仅供学习参考使用,如有不足,还请指正 Thanks♪(・ω・)ノ