Python3爬取CSDN博客信息1.2(GUI版-附完整代码)

往期阅读:
Python3爬取CSDN博客信息1.0(基础版-附完整代码)
Python3爬取CSDN博客信息1.1(GUI版-附完整代码)

一、效果演示

1、 拷贝[我的博客]URL

在这里插入图片描述

2、该版本程序运行效果

在这里插入图片描述

二、涉及模块

  • urllib
  • bs4下的BeautifulSoup
  • wxPython
  • pymysql
  • re
  • time
  • webbrowser
  • os

三、功能说明

在上一个版本(上一个版本传送门)的基础上,对代码结构进行了调整,同时添加了一些新的功能,添加功能如下:

1. 增加对个人博客文章信息的爬取

  • 文章信息表会默认创建到您所输入的本地数据库中
  • 爬取的文章相关数据包括:文章id、文章标题、文章类型、文章链接、发布时间、文章浏览量
  • 至于对文章数据如何加工后分析,后续会提供我自己使用的分析方法。当然有数据库基础的小伙伴建议可以自行创建视图分析

2. 添加保存连接信息功能

  • 连接信息默认会保存在本地磁盘的 d:/blog_connection.txt 文件中
  • 保存连接信息的支持使用快捷键 Ctrl + S
  • 保存时若存在重名的连接信息,会更新之前的信息(重名是指 自定义的连接名称 重复),否则会直接新增一条连接信息
  • 已添加的连接信息,会即时的显示在面板的下拉列表选项中
  • 若手动干预连接信息文件d:/blog_connection.txt,可能会导致程序加载报错

四、代码实现

1、入口/启动代码

import wx
from MyInterface import Interface

class MyApp(wx.App):
    def OnInit(self):
        frame = Interface(None, -1, '我的CSDN博客数据查询工具')
        frame.Show(True)
        return True


app = MyApp(0)
app.MainLoop()

2、GUI界面开发

import os

import wx
import webbrowser as brower

from CrawlArticleData import ArticleData
from CrawlBlogData import BlogData
from DataSourceUtils import DataSourceUtils as dsUtils

"""
图形化界面
"""
class Interface(wx.Frame):
    def __init__(self, parent, id, title):
        super(Interface, self).__init__(parent, id, title)
        # 设置窗口宽高
        self.SetSize(wx.Size(600, 450))
        # 设置界面的图标
        self.SetIcon(wx.Icon('ico/crawl.ico', wx.BITMAP_TYPE_ICO))
        # 默认启动后窗口位置为屏幕居中
        self.Centre()
        self.qt = None
        self.link = None
        self.save = None
        self.select = wx.Menu()

        # 绘制面板
        self.panel = wx.Panel(self, -1)

        w = self.GetSize().width
        h = self.GetSize().height

        # 向面板添加静态标签
        label_combobox_conn = wx.StaticText(self.panel, -1, "选择存在连接:", pos=((w - 300)/2, (h - 300)/2 - 50))
        label_conn_name = wx.StaticText(self.panel, -1, "自定义连接名称:", pos=((w - 300)/2, (h - 300)/2))
        label_url = wx.StaticText(self.panel, -1, "[我的博客]地址:", pos=((w - 300)/2, (h - 300)/2 + 50))
        label_dbname = wx.StaticText(self.panel, -1, "本地数据库名:", pos=((w - 300)/2, (h - 300)/2 + 100))
        label_user = wx.StaticText(self.panel, -1, "数据库用户:", pos=((w - 300)/2, (h - 300)/2 + 150))
        label_pwd = wx.StaticText(self.panel, -1, "数据库密码:", pos=((w - 300)/2, (h - 300)/2 + 200))

        # label_select_conn下拉框
        # 先读取本地连接信息列表,将连接信息存入列表属性中
        self.connect_list = self.read_local_connect()
        self.combobox_conn = wx.ComboBox(self.panel, -1, size=(200, 30), pos=((w - 300) / 2 + 100, (h - 300) / 2 - 50),
                                         choices=self.get_options(self.connect_list),
                                         style=wx.CB_READONLY)
        # label_conn_name文本输入框
        self.entry_conn_name = wx.TextCtrl(self.panel, -1, size=(200, 30), pos=((w - 300)/2 + 100, (h - 300)/2))
        # label_url文本输入框
        self.entry_url = wx.TextCtrl(self.panel, -1, size=(200, 30), pos=((w - 300)/2 + 100, (h - 300)/2 + 50))
        # label_dbname文本输入框
        self.entry_dbname = wx.TextCtrl(self.panel, -1, size=(200, 30), pos=((w - 300)/2 + 100, (h - 300)/2 + 100))
        # label_user文本输入框
        self.entry_user = wx.TextCtrl(self.panel, -1, size=(200, 30), pos=((w - 300) / 2 + 100, (h - 300) / 2 + 150))
        # label_pwd文本输入框
        self.entry_pwd = wx.TextCtrl(self.panel, -1, size=(200, 30), pos=((w - 300) / 2 + 100, (h - 300) / 2 + 200))

        # 面板中添加按钮
        left, top = self.entry_pwd.Position
        self.but_test_connect = wx.Button(self.panel, -1, "测试连接", size=(100, 30), pos=(left, top + 50))
        self.but_search = wx.Button(self.panel, -1, "查询", size=(80, 30), pos=(left + 120, top + 50))
        # 设置按钮的颜色
        self.but_test_connect.SetBackgroundColour("#009ad6")
        self.but_search.SetBackgroundColour("#1d953f")

        # 给按钮绑定事件
        self.Bind(wx.EVT_BUTTON, self.on_test_connect, self.but_test_connect)
        self.Bind(wx.EVT_BUTTON, self.on_search, self.but_search)
        # 给下拉选项添加监听事件
        self.Bind(wx.EVT_COMBOBOX, self.on_combobox, self.combobox_conn)

        # 设置全局变量
        self.url = ''
        self.db_name = ''
        self.db_user = ''
        self.user_pwd = ''
        self.conn_name = ''

        self.init_ui()
    """
        读取本地连接信息文件
    """
    @staticmethod
    def read_local_connect():
        conn_list = []
        if os.path.exists('d:/blog_connection.txt'):
            with open('d:/blog_connection.txt', 'r', encoding='utf-8') as f:
                conn_list = eval(f.read())
        return conn_list

    """
        创建菜单栏
    """
    def init_ui(self):
        menubar = wx.MenuBar()
        '''设置菜单'''
        # file菜单
        file = wx.Menu()
        # file.Append(101, '&Save Connect', 'Save Connection to Local')  # file菜单-选项1
        self.save = wx.MenuItem(file, 101, '&Save Connect\tCtrl+S', 'Save Connection to Local')
        file.Append(self.save)  # file菜单-选项1
        file.AppendSeparator()  # 分割线

        # 设置连接信息二级菜单
        options = wx.Menu()
        for opt in self.connect_list:
            opt = wx.MenuItem(options, 1021, opt['conn_name'], 'Select Connection From Local List')
            self.select.Append(opt)
            # 给每一个连接选项添加监听事件
            self.Bind(wx.EVT_MENU, self.load_conn_info, opt)
            self.select.AppendSeparator()
        file.Append(102, '&Select Connect', self.select)  # file菜单-选项2
        file.AppendSeparator()

        self.qt = wx.MenuItem(file, 103, '&Quit\tCtrl+Q', 'Quit the Application')  # file菜单-选项3
        self.qt.SetBitmap(wx.Bitmap('ico/quit.ico', wx.BITMAP_TYPE_ICO))  # 设置退出的icon
        file.Append(self.qt)

        # help菜单
        help = wx.Menu()
        self.link = wx.MenuItem(help, 201, '&About', 'About Introduction')  # file菜单-选项3
        help.Append(self.link)

        # 菜单加到菜单栏
        menubar.Append(file, '&File')
        menubar.Append(help, '&Help')

        # 程序中创建菜单栏
        self.SetMenuBar(menubar)
        # self.Centre()

        # 给退出按钮绑定事件
        self.Bind(wx.EVT_MENU, self.on_quit, self.qt)
        # 给帮助按钮绑定事件
        self.Bind(wx.EVT_MENU, self.on_link, self.link)
        # 给保存连接按钮绑定事件
        self.Bind(wx.EVT_MENU, self.on_save, self.save)

        # 显示图形化界面
        self.Show()

    '''
        定义一个消息弹出框的函数
    '''
    def alert_error(self, word=""):
        dlg = wx.MessageDialog(None, word, u"警告", wx.YES_NO)
        if dlg.ShowModal() == wx.ID_YES:
            # self.Close(True)
            pass
        dlg.Destroy()

    '''
        定义一个消息弹出框的函数
    '''
    def alert_success(self, word=""):
        dlg = wx.MessageDialog(None, word, u"提示", wx.YES_NO)
        if dlg.ShowModal() == wx.ID_YES:
            pass
        dlg.Destroy()

    '''
    测试连接方法
    '''
    def on_test_connect(self, event, is_alert=True):
        # 连接到本地数据库
        self.db_name = self.entry_dbname.GetValue()
        self.db_user = self.entry_user.GetValue()
        self.user_pwd = self.entry_pwd.GetValue()

        # 判断,查看用户名和密码名是否为空 ,当密码或用户名为空时会出现会导致出错
        if self.db_name and self.db_user and self.user_pwd:
            try:
                conn = dsUtils.connect_default_host_port(self.db_name, self.db_user, self.user_pwd)
                if is_alert:  # 只有测试连接的时候才会弹出成功的提示
                    self.alert_success('连接成功!')
                return True
            except Exception as e:
                print(e)
                self.alert_error('连接失败!')
                return False
            finally:
                conn.close()  # 关闭连接
        else:
            self.alert_error(word='存在未填写信息!')
            return False

    '''
    查询方法
    '''
    def on_search(self, event):
        self.url = self.entry_url.GetValue()
        if self.url == '':
            self.alert_error('URL不能为空!')
            return False
        flag = self.on_test_connect(event, is_alert=False)
        if flag:  # 成功连接,则执行查询操作
            blog_obj = BlogData(url=self.url
                                , db_name=self.db_name
                                , user=self.db_user
                                , pwd=self.user_pwd)
            is_success = blog_obj.main()  # 执行博客数据查询与插入
            article_obj = ArticleData(url=self.url
                                      , db_name=self.db_name
                                      , user=self.db_user
                                      , pwd=self.user_pwd
                                      , blog_account=blog_obj.get_blog_user().get('blog_account')
                                      , blog_alias=blog_obj.get_blog_user().get('blog_alias'))
            is_success2 = article_obj.main()
            if is_success and is_success2:
                self.alert_success('查询并保存本地数据库成功,可前往查看呦')
            else:
                self.alert_error('查询出错了!')

    '''
        退出窗口
    '''
    def on_quit(self, event):
        self.Close()

    '''
        帮助方法
    '''
    def on_link(self, event):
         brower.open('https://blog.csdn.net/qq_19314763/article/details/110951204')

    '''
        保存连接信息到本地
    '''
    def on_save(self, event):
        # 将连接信息赋值到self对象中
        self.conn_name = self.entry_conn_name.GetValue()
        self.url = self.entry_url.GetValue()
        self.db_name = self.entry_dbname.GetValue()
        self.db_user = self.entry_user.GetValue()
        self.user_pwd = self.entry_pwd.GetValue()
        if self.conn_name != '':
            flag = False
            for conn in self.connect_list:
                if conn['conn_name'] == self.conn_name:
                    flag = True
                    # 如果已经存在该名称的连接,则进行修改操作
                    conn['url'] = self.url
                    conn['db_name'] = self.db_name
                    conn['db_user'] = self.db_user
                    conn['user_pwd'] = self.user_pwd
                    break
            if flag is False:  # 不存在,则直接新增
                with open('d:/blog_connection.txt', 'w', encoding='utf-8') as f:
                    info_dict = {'conn_name': self.conn_name, 'url': self.url, 'db_name': self.db_name, 'db_user': self.db_user, 'user_pwd': self.user_pwd}
                    self.connect_list.append(info_dict)
                    f.write(str(self.connect_list))  # 把列表转化为str存入文件

            print('----------连接信息保存本地成功!-----------')
            self.alert_success(word='保存成功啦啦啦')
            self.combobox_conn.Set(self.get_options(self.connect_list))  # 重新设置选项,相当于刷新选项列表
        else:
            self.alert_error(word='请输入连接名称!')

    """
        根据用户选择的连接名称读取连接信息(该方式行不通,无法获取到菜单栏中选择的项)
    """
    def load_conn_info(self, event):
        self.alert_success('菜单栏里选择连接的方式行不通!')

    '''
        根据用户选择的连接名称读取连接信息
    '''
    def on_combobox(self, event):
        selected_conn_name = event.GetString()  # 拿到选择的连接名称
        # 根据连接名称将相关连接信息赋值到对应的输入框中
        for conn in self.connect_list:
            if conn['conn_name'] == selected_conn_name:
                self.entry_conn_name.SetValue(conn['conn_name'])
                self.entry_url.SetValue(conn['url'])
                self.entry_dbname.SetValue(conn['db_name'])
                self.entry_user.SetValue(conn['db_user'])
                self.entry_pwd.SetValue(conn['user_pwd'])

    '''
        根据连接信息列表,提取出连接信息名称列表,作为下拉框的选项内容
    '''
    @staticmethod
    def get_options(conn_list):
        conn_name_list = []
        for conn in conn_list:
            conn_name_list.append(conn['conn_name'])
        return conn_name_list


3、爬取博客信息

import urllib.request as request
import urllib.error as error
import time
from bs4 import BeautifulSoup
import re
from DataSourceUtils import DataSourceUtils as dsUtils


class BlogData:
    def __init__(self, url, db_name, user, pwd):
        self.url = url
        self.db_name = db_name
        self.db_user = user
        self.user_pwd = pwd
        self.account = ''
        self.alias = ''
        # self.main()
    """
    爬取整个HTML页面
    """
    def download(self, crawl_url, num_retries=3):
        # 设置用户代理
        headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
                          'Chrome/72.0.3626.121 Safari/537.36',
        }
        # 设置请求的URL
        req = request.Request(crawl_url, headers=headers)
        try:
            # 开始爬取整个HTML代码
            crawl_html = request.urlopen(req).read().decode("utf-8")

        # 此处异常用于处理,csdn服务器异常后导致爬取失败
        except error.URLError as e:
            print("download error:", e.reason)
            crawl_html = None
            if num_retries > 0:
                if hasattr(e, "code") and 500 <= e.code <= 600:
                    time.sleep(5000)  # 主线程睡眠5s后再重新访问,最多访问3次,也就是如果程序开始执行10s后,csdn服务器始终未正常启动,则此次爬取失败
                    return self.download(crawl_url, num_retries-1)
        return crawl_html

    """
    解析HTML获取页面上的10组数据
    """
    def parse_page(self, page_html):
        # 声明一个包含10组key的字典data_dict
        data_dict = {'积分': '', '粉丝': '', '获赞': '', '评论': '', '收藏': ''
                     , '原创': '', '周排名': '', '总排名': '', '访问': '', '等级': ''
                     , '账号': '', '昵称': ''}

        # 开始解析html
        soup = BeautifulSoup(page_html, "html.parser")

        # 解析class='text-center'的所有<dl>标签列表
        # 方式一
        # dl_list = soup.find_all(name='div', attrs={'class': re.compile('text-center')})
        # 方式二
        dl_list = soup.find_all('dl', class_='text-center')

        # 遍历dl标签列表,获取到每一个dl标签,将目标数值存入字典data_dict
        for dl in dl_list:
            # print(dl)
            dd_name = dl.select('dd')[0].text  # 读取该dl标签的子标签dd的文本内容
            dd_title = dl.get('title')  # 读取该dl标签的title属性值
            for k in data_dict.keys():  # 遍历data_dict字典,将匹配的数值存入字典中
                if dd_name == k:
                    data_dict[k] = dd_title

        # 获取账号和昵称信息
        self_info_list = soup.find_all('a', id='uid')  # 根据id获取a标签元素
        self.alias = self_info_list[0].get('title')
        self.account = self_info_list[0].select('span')[0].get('username')
        data_dict.update({"账号": self.account, "昵称": self.alias})

        # data_dict添加爬取时间的信息
        data_dict.update({"爬取时间": time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())})

        return data_dict

    """
    判断表是否存在
    """
    def table_exists(con, table_name):  # 这个函数用来判断表是否存在
        sql = "show tables;"
        con.execute(sql)
        tables = [con.fetchall()]
        table_list = re.findall('(\'.*?\')', str(tables))
        table_list = [re.sub("'", '', each) for each in table_list]
        if table_name in table_list:
            return 1        # 存在返回1
        else:
            return 0        # 不存在返回0

    '''
    将字典数据存入数据库
    '''
    def save_to_mysql(self, data_obj):
        # db = input('请输入本地数据库名:')
        # username = input('请输入数据库用户名:')
        # password = input('请输入数据库密码:')

        # 连接数据库
        conn = dsUtils.connect_default_host_port(self.db_name, self.db_user, self.user_pwd)
        # 建立游标,用于数据库插入
        cursor = conn.cursor()

        # # 校验数据库是否存在博客数据记录表
        # table_count = table_exists(conn, 'CSDN_SELF_BLOG_DATA')
        # # 如果数据库不存在该表,则创建
        # if table_count == 0:
        sql_create = """CREATE TABLE IF NOT EXISTS `csdn_self_blog_data` (
                                      `id` bigint NOT NULL AUTO_INCREMENT,
                                      `account` varchar(100) DEFAULT NULL,
                                      `alias` varchar(100) DEFAULT NULL,
                                      `grade` int DEFAULT NULL,
                                      `count_fan` int DEFAULT NULL,
                                      `count_thumb` bigint DEFAULT NULL,
                                      `count_comment` bigint DEFAULT NULL,
                                      `count_star` int DEFAULT NULL,
                                      `count_original` int DEFAULT NULL,
                                      `rank_week` bigint DEFAULT NULL,
                                      `rank_all` bigint DEFAULT NULL,
                                      `count_scan` bigint DEFAULT NULL,
                                      `blog_level` varchar(100) DEFAULT NULL,
                                      `crawl_time` datetime DEFAULT NULL,
                                      `start_hour` int DEFAULT NULL,
                                      `end_hour` int DEFAULT NULL,
                                      `crawl_date` date DEFAULT NULL,
                                      PRIMARY KEY (`id`)
                                    ) ENGINE=InnoDB DEFAULT CHARSET=utf8
                                    """
        cursor.execute(sql_create)
        # print('==========表创建完成=========')

        # 创建SQL语句并往数据库插入数据
        curr_date = time.strftime("%Y-%m-%d", time.localtime())
        curr_time = data_obj['爬取时间']
        sql_insert = """insert into csdn_self_blog_data(
                                     account, alias, grade, count_fan, count_thumb
                                    ,count_comment, count_star, count_original, rank_week, rank_all
                                    ,count_scan, blog_level, crawl_time, start_hour, end_hour
                                    ,crawl_date)
                        values( %s, %s, %s, %s, %s
                               ,%s, %s, %s, %s, %s
                               ,%s, %s, %s, %s, %s
                               ,%s)"""
        values_list = [data_obj['账号'], data_obj['昵称'], data_obj['积分'], data_obj['粉丝'], data_obj['获赞']
                       , data_obj['评论'], data_obj['收藏'], data_obj['原创'], data_obj['周排名'], data_obj['总排名']
                       , data_obj['访问'], data_obj['等级'], curr_time, curr_time[11:13], int(curr_time[11:13]) + 1
                       , curr_date]
        cursor.execute(sql_insert, tuple(values_list))
        conn.commit()  # 提交请求,不然不会插入数据
        conn.close()
        print("======================博客数据-保存数据库成功!=======================")
        return True

    """
        获取用户信息
    """
    def get_blog_user(self):
        return {'blog_account': self.account, 'blog_alias': self.alias}

    """
    主程序
    """
    def main(self):
        # url = input('请输入您的CSDN网站[我的博客]URL地址:')

        # url = "https://blog.csdn.net/qq_19314763?spm=1010.2135.3001.5113"  # 使用自己的CSDN[我的博客]的URL地址
        # 1、获取整个HTML
        html = self.download(self.url)
        # 2、解析HTML获取目标数据,并存储到字典中
        dict_obj = self.parse_page(html)

        # 打印字典信息,查看效果使用
        # for key, value in dict_obj.items():
        #     print(key + ' = ' + value)

        # 3、将字典数据存入MySQL数据库
        return self.save_to_mysql(dict_obj)




4、爬取文章信息

import urllib.request as request
import urllib.error as error
import time
from bs4 import BeautifulSoup
import re
from DataSourceUtils import DataSourceUtils as dsUtils

"""
博客文章爬取类
"""
class ArticleData:
    def __init__(self, url, db_name, user, pwd, blog_account, blog_alias):
        self.url = url
        self.db_name = db_name
        self.db_user = user
        self.user_pwd = pwd
        self.blog_account = blog_account
        self.blog_alias = blog_alias
        # self.main()
    """
    爬取整个HTML页面
    """
    def download(self, crawl_url, num_retries=3):
        # 设置用户代理
        headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
                          'Chrome/72.0.3626.121 Safari/537.36',
        }
        # 设置请求的URL
        req = request.Request(crawl_url, headers=headers)
        try:
            # 开始爬取整个HTML代码
            crawl_html = request.urlopen(req).read().decode("utf-8")

        # 此处异常用于处理,csdn服务器异常后导致爬取失败
        except error.URLError as e:
            print("download error:", e.reason)
            crawl_html = None
            if num_retries > 0:
                if hasattr(e, "code") and 500 <= e.code <= 600:
                    time.sleep(5000)  # 主线程睡眠5s后再重新访问,最多访问3次,也就是如果程序开始执行10s后,csdn服务器始终未正常启动,则此次爬取失败
                    return self.download(crawl_url, num_retries-1)
        return crawl_html

    """
    解析HTML获取页面的博客文章数据
    """
    def parse_page(self, page_html):
        # 声明一个空列表data_list
        data_list = []

        # 开始解析html
        soup = BeautifulSoup(page_html, "html.parser")

        # 解析class='article-item-box'的所有<div>标签列表
        article_item_box_list = soup.find_all('div', class_='article-item-box')
        for item in article_item_box_list:
            article_id = item.get('data-articleid')
            a_tag = item.select('a')[0]
            article_url = a_tag.get('href')
            # print(a_tags[0].select('span')[0].text)  # soup获取子元素方式1
            article_type = a_tag.span.text  # soup获取子元素方式2
            article_title = a_tag.text.replace(' ', '').replace('\n', '').replace(article_type, '')
            info = item.select('div')[0].select('span')
            publish_time = info[0].text
            read_num = info[1].text
            item_dict = {}
            item_dict.update({'article_id': article_id})
            item_dict.update({'article_title': article_title})
            item_dict.update({'article_type': article_type})
            item_dict.update({'article_url': article_url})
            item_dict.update({'publish_time': publish_time})
            item_dict.update({'read_num': read_num})
            data_list.append(item_dict)

        return data_list

    """
    判断表是否存在
    """
    def table_exists(con, table_name):  # 这个函数用来判断表是否存在
        sql = "show tables;"
        con.execute(sql)
        tables = [con.fetchall()]
        table_list = re.findall('(\'.*?\')',str(tables))
        table_list = [re.sub("'", '', each) for each in table_list]
        if table_name in table_list:
            return 1        # 存在返回1
        else:
            return 0        # 不存在返回0

    '''
    将data_list列表数据存入数据库
    '''
    def save_to_mysql(self, data_list):
        # 连接数据库
        conn = dsUtils.connect_default_local()
        # 建立游标,用于数据库插入
        cursor = conn.cursor()
        # 如果表不存在,先创建表
        sql_create = """CREATE TABLE IF NOT EXISTS `csdn_blog_article_data` (
                                      `id` bigint NOT NULL AUTO_INCREMENT,
                                      `account` varchar(100) DEFAULT NULL,
                                      `alias` varchar(100) DEFAULT NULL,
                                      `article_id` bigint DEFAULT NULL,
                                      `article_title` varchar(200) DEFAULT NULL,
                                      `article_type` varchar(50) DEFAULT NULL,
                                      `article_url` varchar(200) DEFAULT NULL,
                                      `publish_time` varchar(32) DEFAULT NULL,
                                      `read_num` int DEFAULT NULL,
                                      `start_hour` int DEFAULT NULL,
                                      `end_hour` int DEFAULT NULL,
                                      `crawl_date` date DEFAULT NULL,
                                      `crawl_time` datetime DEFAULT NULL,
                                      PRIMARY KEY (`id`)
                                    ) ENGINE=InnoDB DEFAULT CHARSET=utf8
                                    """
        cursor.execute(sql_create)

        # 遍历列表,分别执行插入操作
        for dict_obj in data_list:
            self.insert_to_db(cursor, dict_obj)
        conn.commit()  # 提交请求,不然不会插入数据
        dsUtils.close(cursor, conn)
        print("======================文章数据-保存数据库成功!=======================")
        return True

    """
        将字典数据插入数据库
    """
    def insert_to_db(self, cursor, data_obj):
        # 创建SQL语句并往数据库插入数据
        curr_date = time.strftime("%Y-%m-%d", time.localtime())
        curr_time = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
        start_hour = curr_time[11:13]
        end_hour = int(start_hour) + 1
        sql_insert = """insert into csdn_blog_article_data(
                                             account, alias, article_id, article_title
                                            ,article_type, article_url, publish_time, read_num
                                            ,start_hour, end_hour, crawl_date, crawl_time)
                                values( %s, %s, %s, %s
                                       ,%s, %s, %s, %s
                                       ,%s, %s, %s, %s)"""
        values_list = [self.blog_account, self.blog_alias, data_obj['article_id'], data_obj['article_title']
                       , data_obj['article_type'], data_obj['article_url'], data_obj['publish_time'], data_obj['read_num']
                       , start_hour, end_hour, curr_date, curr_time]
        cursor.execute(sql_insert, tuple(values_list))

    """
    主程序
    """
    def main(self):
        # url = input('请输入您的CSDN网站[我的博客]URL地址:')

        # url = "https://blog.csdn.net/qq_19314763?spm=1010.2135.3001.5113"  # 使用自己的CSDN[我的博客]的URL地址
        # 1、获取整个HTML
        html = self.download(self.url)
        # 2、解析HTML获取目标数据,并存储到列表中
        dict_list = self.parse_page(html)

        # 3、将字典数据存入MySQL数据库
        return self.save_to_mysql(dict_list)

# 单独测试
# url = 'https://blog.csdn.net/qq_19314763?spm=1011.2124.3001.5113'
# db_name = 'csdndb'
# user = 'root'
# user_pwd = '123456'
# is_success = ArticleData(url, db_name, user, user_pwd, 'qq_19314763', '迟到_啦')
# print(is_success)

5、数据源工具类

import pymysql


"""
数据源工具类
"""
class DataSourceUtils:
    @staticmethod
    def connect_default_local():
        conn = pymysql.connect(
            host="127.0.0.1",
            port=3306,  # 端口号
            user='root',  # 数据库用户
            password='123456',  # 数据库密码
            database='csdndb'  # 要连接的数据库名称
        )
        return conn

    @staticmethod
    def connect_default_host_port(db_name, db_user, user_pwd):
        conn = pymysql.connect(
            host='127.0.0.1',
            port=3306,  # 端口号
            user=db_user,  # 数据库用户
            password=user_pwd,  # 数据库密码
            database=db_name  # 要连接的数据库名称
        )
        return conn

    @staticmethod
    def connect_default_port(host, db_name, db_user, user_pwd):
        conn = pymysql.connect(
            host=host,
            port=3306,  # 端口号
            user=db_user,  # 数据库用户
            password=user_pwd,  # 数据库密码
            database=db_name  # 要连接的数据库名称
        )
        return conn

    @staticmethod
    def connect_all_params(host, port, db_name, db_user, user_pwd):
        conn = pymysql.connect(
            host=host,
            port=port,  # 端口号
            user=db_user,  # 数据库用户
            password=user_pwd,  # 数据库密码
            database=db_name  # 要连接的数据库名称
        )
        return conn

    @staticmethod
    def close(cursor, conn):
        cursor.close()
        conn.close()

6、完整代码
前往下载

五、参考链接

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

迟到_啦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值