bs4主要知识点介绍及实例解析---利用bs4爬取伯乐在线(分别存储在数据库和xls表中)

                                           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♪(・ω・)ノ

猜你喜欢

转载自blog.csdn.net/A_fool_Program_ape/article/details/81631279
今日推荐