当前位置:   article > 正文

Python爬虫——爬取博物馆新闻 + 情感倾向分析 + 导入数据库_python爬虫情感分析

python爬虫情感分析

一、环境

  1. windows10
  2. python3.7
  3. mysql8(本地+阿里云)

二、出现的问题及注意事项

  1. 这是一个小组任务,而且对于每个人来说都是全新的知识,但是在前期没有充分沟通学习方式,导致大家各自学习,走了许多弯路。
  2. 爬下来的数据在处理上欠考虑,给后续步骤带来麻烦。
  3. 完成本组任务后和博物馆信息组的同学交流,发现还存在反爬技术。对此我的想法是,我学的东西能够完成我的任务,那就没必要深入学习爬虫,毕竟这不是我的主要兴趣而每个人的时间都是有限的。这个学期各种事情都堆在一起,很考验时间管理的能力,要分清主次,一门2.5学分的选修课不值得我花那么多时间。
  4. 当然要向别人学习,别的团队做得更好那就向他们学习。但是也不要一味和别人比较,“他强由他强,清风拂山冈”。别的团队学习了怎么应对反扒,不意味着我们也需要去学,还是那句话,我们学的东西足够达到一个还能过得去的程度,这就可以了。毕竟,这是软件工程课,爬虫、前后端其实都不是重点,既然老师不负责任地布置了这种大作业,那我也没必要认真对待。别人是大佬,别的组有大佬,他们做得好,这和我没关系。

三、爬虫思路

由于本人是初学者,有说的不对的地方敬请指正。
首先,要找一个教程,B站上有很多,不要看书或者看博客,因为视频能展示更多信息,很多会踩的坑是很难用文字一一表述出来的,那样会使文章显得臃肿,而在视频里可能就是半分钟的debug,而且视频能帮你快速建立对新知识的整体认识。举例来说,在学习的前期,我们组的每一个人都以为爬虫可以一套代码爬很多网站,在中期,其他组(前端、后端)的同学说数据库里新闻太少、博物馆信息太少,我们也得和他们解释,爬虫没有那么智能,对于不同的网站(通常页面结构不同)需要不同的爬虫代码,想爬一个网站就得先查看它的页面结构。你看,这么简单的道理,对于新手来说确实是一个认知上的障碍。下图中,一个个html标签组成了这个网页,不同的网页用的标签是不同的。
在这里插入图片描述
第二,现代网页很少有不用AJAX动态加载的,也就是说对一个url发请求不会得到想要的信息。拿新闻来说,我们选择对新华网上博物馆的新闻进行爬取,在新华网(或者人民网、腾讯新闻等)搜索栏输入“故宫博物院”会跳转到一个网页,这个网页就是动态加载出来的。很多文字教程并没有讲这个,而只是讲怎么爬一个静态的html页面。上图中,是没办法通过对该页面的网址作解析得到所选的<a></a>标签的。事实上,我之前一直认为遇到任何问题都应该到官网找答案,但是在beautifulsoup、scrapy官网耗了很久,虽然会看到一些dynamic load之类的词,但实际上并不清楚,同样的事视频里10分钟就讲完了,这不比看官方文档快?下图中,切换到network标签,选择XMR,刷新页面,就可以看到抓到一个包,在header中可以看到实际上我们要发请求的网址,以及需要哪些参数。
在这里插入图片描述
第三,对于动态请求的页面的处理,简单来说就是加载这个页面的时候,我们并不从这个页面的html获取数据,实际上是向某个地址(人民网用的是elasticsearch)发送了带有一些参数的请求,我们就是要获取这个地址,并根据需要更换参数。在这次作业中,博物馆的名字就是一个参数,搜索的博物馆的新闻一页放不下的时候,页码也是一个参数。页面结构、获取所谓的请求地址都是用浏览器的“开发者工具"的。要获取返回的数据,你可以在上图中切换到与header同级的response标签,你会看到一个JSON格式的字符串,格式化以后看得清楚一点(如下图)。这一条所说的你只要在那些教程里看上一两个视频就都会了。
在这里插入图片描述

第四,动态请求的页面上有我们所需的各条新闻的链接,当我们获取这些动态加载出来的链接之后,就可以按照解析静态网页的方式解析这些网址了。新华网、人民网都是分主站新闻、地方频道的,别的细分种类还包括视频新闻等,他们的结构是不同的。在本次任务中,我们选择了先只爬主站新闻,后面再加入了地方频道(我们只需要往数据库里存文本和图片地址,不考虑视频),事实上,新华网的地方频道也是由两种主要结构和其他一些乱七八糟的结构(这些就不爬了)组成的。这都是在爬取的过程中发现的,没有什么捷径。
地方频道
主站新闻

第五,发送请求的是requests包,解析返回来的数据的是beautifulsoup包,本次任务并没有用到scrapy(一个框架,而不只是包)和selenium(最复杂也最强大)。主要就是用find,find_all,select等方法找标签,具体学习上beautifulsoup官网或别的文字教程即可(这个可以有)。
第六,考虑到网页动态返回的数据格式(一般是json),处理数据、保存文件、传数据库的统一性,最好都使用json格式存储数据。
第七,编码相关的问题遇到多次,这里充分体现了面向百度/谷歌编程的重要性。

  1. 有很多地方涉及到编码的问题,不报错,你都不知道你看到的是不是你看到的,也不知道为什么你看到的不是你想看到的。
  2. 网页返回的数据有的是gbk,有的是utf-8;用powershell运行程序时的活动页代码(chcp)默认是936(简体中文),有时要切换成65001(utf-8);vscode默认显示编码是utf-8,而有的时候又需要切换成gbk才能正常显示中文文件;requests请求回来的数据照理说是utf-8(ajax请求头里写了返回数据的编码格式),vscode编码也是utf-8,但会乱码;读写json文件要指定编码;python文件要指定编码(以前听都没听说过);json(javascript)中布尔真是true,python中布尔真是True。以下问题都是我遇到的,具体报什么错已经不完全记得了。
  3. 打开json文件时要指定open()编码为utf-8(虽然这应该是默认值),同时json.dump()中要把ensure_ascii置为False,否则就只会正常写入ASCII码范围内的字符,不在其列的中文字符就会以\xxxx乱码的形式出现,这时就算再用gbk或utf-8读也没用,因为这时存的就是\xxxx这个字符串。
with open(f"新华网_{keyword}.json", 'w', encoding="utf-8") as f:
    json.dump(all_news, f, ensure_ascii=False)
  • 1
  • 2
  1. response = requests.get(url, headers=headers)之后要加response.encoding = response.apparent_encoding,我试过不加,或指定为utf-8和gbk,都会乱码,只能用apparent_encoding,方法是网上找的,原理不清楚。
  2. 因为要进行文本情感倾向分析,所以需要将大段的新闻内容(字符串)传给函数。字符串比较短的时候什么事都没有,比较长就会报“Non-UTF-8 code starting with”的错,但我是以同一个字开头的啊,只是长度变长了而已。解决方法是在文件最开头(如果开头有注释的话也得在其之后,反正就是在第一行)加上# -*- coding:utf-8 -*-
  3. 阿里云NLP服务返回的json格式(其实是bytes格式,要用json.loads转)有问题,将一系列键值对装在双引号里成了字符串,导致没法用键值访问result的内容(正面/中立/负面)。python中用ast.literal_eval可以将字符串转成字典(详细用法就不展开了,还有其他用处),但是这时一直报“畸形的字符串”(大概是这个意思),原因就是这个方法不像json包提供的方法会处理true/True,需要先把true替换成True。
data = resp_obj["Data"].replace("true", "True")
data = ast.literal_eval(data)
  • 1
  • 2
  1. 爬下来的数据中会有换行符、缩进以及其他莫名奇妙的字符,全都删掉。(影不影响文意就不管了,反正只是作业,不用搞那么仔细)
p_text = p.text.replace("\u3000", "").replace('\n', "").replace('\r', "").replace('\t', "").replace('\xa0', "")
  • 1
  1. 真的遇到很多问题和报错,现在也记不起来了,等记起来再补上。

第八,文本情感倾向分析直接调用阿里云的服务,相关操作按文档来就行(别的也找不到什么资料)。百度、腾讯、华为等其他公司也有这种开放的AI能力提供,也可以选择。
第九,为避免数据库里出现重复记录,要实现增量更新。实现思路是:每次爬取前都会先扫描当前目录下的json文件(如果有news_inserted.json也要读入),读取它们的内容,获取标题(后面会用到,因为某个标题可能对应多个报道同一个新闻的不同页面,对这些新闻得去重,靠的是标题),统计新闻条数,然后写入news_inserted.json,将其他json移入当前目录下的子文件夹backup。每次爬完后都可能在当前目录下产生“新华网_XXX.json”文件,json2mysql.py会把这些文件中的数据导入数据库,而不会把news_inserted.json中的数据导入数据库。所以爬完就要紧跟着导入,不然数据就会被归档。
在这里插入图片描述

四、代码

(1)爬虫

# -*- coding:utf-8 -*-

# 加入情感倾向分析(v5)
# 1、调用阿里云NLP服务实现情感倾向分析
# 2、解决编码问题,在首行加# -*- coding:utf-8 -*-。注意是有井号的,而且一定是全文的首行,即,包括文首的注释,都得在这句之后
#   (1)短文本不用加也行,长文本就会报Non-UTF-8 code starting with的错误,原因我不知道

# 针对更新的需求进行调整(v4)
# 1、实现地方频道的爬取
# 2、在结果json中加入title,省去v3中提取symbol的步骤,改为判断title,相应地,要改导入数据库的文件
# 3、测试说明
#   (1)先用少一点的博物馆和少一点的curPage
#   (2)再加curPage
#   (3)再加别的博物馆

# 针对更新的需求进行调整(v3)
# 1、每次运行这个脚本之前都要对当前目录下已有的json文件进行处理,以实现导入数据库的只有增量部分,同时保留历史版本

# 针对传数据库的要求进行调整(v2)
# 1、每条新闻的图片最多1张(可以没有,但是不能多,因为表中目前只给一个位置
# 2、每个每条记录都要完整包含来源、博物馆名字,而不是上一个版本那样一个博物馆一个json
# 3、使用navicat导入json的功能

import requests
import json
import csv
import os
import ast
from bs4 import BeautifulSoup
import shutil
from aliyunsdkalinlp.request.v20200629 import GetSaChGeneralRequest
from aliyunsdkcore.client import AcsClient
from aliyunsdkcore.acs_exception.exceptions import ClientException
from aliyunsdkcore.acs_exception.exceptions import ServerException

def get_url_list(origin_url):
    url = origin_url
    # 用开发者工具查看ajax包时,在请求头里发现请求的Content-Type的格式和编码是application/json;charset=UTF-8。不加会有乱码。
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) \
                       Chrome/67.0.3396.99 Safari/537.36",
        'Content-Type': 'application/json;charset=UTF-8'
    }
    # 存放详情页地址(静态,实际要爬的网页)的列表
    url_list = []
    try:
    	# 这里的实际请求url中就带了参数,用的是get方法
    	# 有的网页实际请求url中不带参数,用的是post方法,这时要把参数以data参数给出(详见视频教程)
        json_urls = requests.get(url=url, headers=headers).json()
        # 观察返回的json数据,发现所要的url在如下位置
        results = json_urls["content"]["results"]
        if results is None:
            return
        for result in results:
            url_list.append(result["url"])
        print(f"正在获取{keyword}的第{curPage}页新闻。。。")
        return url_list
    except Exception as e:
        print(e)    


# 地方频道
# eg. http://www.js.xinhuanet.com/2021-02/07/c_1127073849.htm
#     http://www.zj.xinhuanet.com/2020-06/13/c_1126110863.htm
def crawl_news_A(keyword, url, article, soup, titles):
	# 找标题
    h1 = article.find_next("h1", id="title")
    if h1 is None:
        return
    # 把莫名奇妙的字符去掉
    title = h1.text.replace("\n", "").replace('\r', "").replace('\u3000', ",").strip().replace(' ', ",")
    # 判断是不是重复,避免传进数据库很多相似度很高的新闻
    if title in titles:
        print("重复的新闻!")
        return
    # 在实际爬取过程中发现,搜索结果有时候是模糊匹配,比如搜“上海博物馆”,返回的有“上海自然博物馆”的新闻。报错中提供url,以供确认
    if keyword not in title:
        print(f"由于某些原因,{url} 似乎不是 {keyword} 相关的新闻  :(")
        return
    titles.append(title)
	
	# 获取日期(三种页面获取时间方式也不同)
    time = soup.find("span", class_="time").text.replace("\n", "").replace(" ", "").replace('\r', "")
    year = time.split('年')[0]
    month = time.split('年')[1].split('月')[0]
    day = time.split('年')[1].split('月')[1].split('日')[0]
    date = year + "." + month + "." + day
	
	# 在这个页面结构中可以获得来源(不一定是新华网),其他两个页面似乎不行,所以我都默认是新华网了
    source = soup.find("em", id="source").text.replace("\n", "").replace(" ", "").replace('\r', "")
	
    content = []
    img = []
    ps = article.find("div", class_="article").find_all("p")
    for p in ps:
        p_text = p.text.replace("\u3000", "").replace('\n', "").replace('\r', "").replace('\t', "").replace('\xa0', "")
        # XXX摄影,图片来自新华在线。。。这种信息是无用的。如果是单独成段,就删掉,否则保留。
        if "摄" in p_text or "图片来源" in p_text:
            if len(p_text) < 50 and p_text.find("记者", -15):  
                continue
        content.append(p_text)
		# 如果有图片的话就获取图片链接。观察得知页面中给出的是图片的相对地址,要和页面地址中的一部分作拼接才是完整地址
        url_page = '/'.join(url.split('/')[:-1])
        p_imgs = p.find_all("img")
        for p_img in p_imgs:
            img.append(url_page + '/' + p_img.get("src"))
    content = ''.join(content) 
    # 代码不完善,有时会爬到错误的东西,导致内容过长。而且我们数据库对新闻限制10000字
    if len(content) > 9900:
        print(f"出错了!文章内容过长,请确认 {url}")
        return
    # 有时又会出现把“XXX摄影”之类的删掉以后新闻内容部分为空的情况,这种也不要
    if len(content) == 0:
    	print(f"文章长度为0? {url}")
    	return
    # 阿里云NLP服务限制文本长度不超过1000
    content_to_test = content if len(content) < 900 else content[:900]
   
    news = {}
    news["museum"] = keyword
    news["time"] = date
    news["type"] = get_sentiment(content_to_test)
    news["content"] = content
    news["photo"] = img[0] if (len(img) > 0) else ''
    news["source"] = source if (source is not None) else "新华网"
    news["title"] = title

    return news


# 正文频道
# eg. http://www.xinhuanet.com/2020-09/02/c_1126445038.htm
#     http://www.xinhuanet.com/expo/2019-11/18/c_1210358665.htm
def crawl_news_B(keyword, url, p_detail, soup, titles):
    h_title = soup.find("div", class_="h-title")
    if h_title is None:
        return
    title = h_title.text.replace("\n", "").replace('\r', "").replace('\u3000', ",").strip().replace(' ', ",")
    if title in titles:
        print("重复的新闻!")
        return
    if keyword not in title:
        print(f"由于某些原因,{url} 似乎不是 {keyword} 相关的新闻,其标题是《{title}》")
        return
    titles.append(title)

    time = soup.find("span", class_="h-time").text.replace("\n", "").replace(" ", "").replace('\r', "")[:10]
    date = time.split('-')[0] + "." + time.split('-')[1] + "." + time.split('-')[2]

    content = []
    img = []
    ps = p_detail.find_all("p")
    for p in ps:
        if p.find("a"):
            continue
        p_text = p.text.replace("\u3000", "").replace('\n', "").replace('\r', "").replace('\t', "").replace('\xa0', "")
        if "摄" in p_text or "图片来源" in p_text:
            if len(p_text) < 50 and p_text.find("记者", -15):  
                continue
        content.append(p_text)

        url_page = '/'.join(url.split('/')[:-1])
        p_imgs = p.find_all("img")
        for p_img in p_imgs:
            img.append(url_page + '/' + p_img.get("src"))
    content = ''.join(content) 
    if len(content) > 9900:
        print(f"出错了!文章内容过长,请确认 {url}")
        return
    if len(content) == 0:
    	print(f"文章长度为0? {url}")
    	return
    content_to_test = content if len(content) < 900 else content[:900]
    
    news = {}
    news["museum"] = keyword
    news["time"] = date
    news["type"] = get_sentiment(content_to_test)
    news["content"] = content
    news["photo"] = img[0] if (len(img) > 0) else ''
    news["source"] = "新华网"
    news["title"] = title

    return news


# 主站
# eg. http://m.xinhuanet.com/2021-04/30/c_1127399187.htm
#     http://m.xinhuanet.com/2021-04/30/c_1127398081.htm
def crawl_news_main(keyword, url, head_line, soup, titles):
    h1 = head_line.find_next("h1")
    if h1 is None:
        print("h1 is None")
        return  
    title = h1.find_next("span").text.replace("\n", "").replace('\r', "").replace('\u3000', ",").strip().replace(' ', ",")
    if title in titles:
        print("重复的新闻!")
        return
    if keyword not in title:
        print(f"由于某些原因,{url} 似乎不是 {keyword} 相关的新闻  :(")
        return
    titles.append(title)
    
    header_time = soup.find("div", class_="header-time")
    year = header_time.find("span", class_="year").find("em").text.replace("\n", "").replace(" ", "").replace('\u3000', "")
    day = header_time.find("span", class_="day").text.replace(" ", "").split('/')
    date = year + "." + day[0] + "." + day[1]

    content = []
    img = []
    ps = soup.find("div", id="detail").find_all("p")
    for p in ps:
        p_text = p.text.replace("\u3000", "").replace('\n', "").replace('\r', "").replace('\t', "").replace('\xa0', "")
        if "摄" in p_text or "图片来源" in p_text:
            if len(p_text) < 50 and p_text.find("记者", -15):  
                continue
        content.append(p_text)

        url_page = '/'.join(url.split('/')[:-1])
        p_imgs = p.find_all("img")
        for p_img in p_imgs:
            img.append(url_page + '/' + p_img.get("src"))
    content = ''.join(content) 
    if len(content) > 9900:
        print(f"出错了!文章内容过长,请确认 {url}")
        return
    if len(content) == 0:
    	print(f"文章长度为0? {url}")
    	return
    content_to_test = content if len(content) < 900 else content[:900]

    news = {}
    news["museum"] = keyword
    news["time"] = date
    news["type"] = get_sentiment(content_to_test)
    news["content"] = content
    news["photo"] = img[0] if (len(img) > 0) else ''
    news["source"] = "新华网"
    news["title"] = title

    return news


def crawl_news(url_list, keyword, titles):
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) \
                       Chrome/67.0.3396.99 Safari/537.36"
    }
    
    all_news = {}
    all_news["data"] = []
    
    for url in url_list:

        try:
            response = requests.get(url, headers=headers)
            response.encoding = response.apparent_encoding
            soup = BeautifulSoup(response.text, "lxml")

            head_line = soup.find("div", class_="head-line")
            if head_line is None:
                article = soup.find("div", id="article")
                p_detail = soup.find("div", id="p-detail")
                if article is not None:  # 地方频道
                    news = crawl_news_A(keyword, url, article, soup, titles)
                    if news is None:
                        error = "地方频道爬取失败"
                elif p_detail is not None:  # 正文频道
                    news = crawl_news_B(keyword, url, p_detail, soup, titles)
                    if news is None:
                        error = "正文频道爬取失败"
                else:
                    news = None
                    error = "不符合主站、正文、地方频道三种页面布局"
            else:  # 主站
                news = crawl_news_main(keyword, url, head_line, soup, titles)   
                if news is None:
                    error = "主站爬取失败"
            if news is not None:
                all_news["data"].append(news)
            else:
                print(f"爬取 {url} 对应的新闻出现错误:{error}")

        except Exception as e:
            print(e)
            
	# 写入这家博物馆在新华网的新闻到json,注意编码
    if len(all_news["data"]) > 0:
        with open(f"新华网_{keyword}.json", 'w', encoding="utf-8") as f:
            json.dump(all_news, f, ensure_ascii=False)


def update_check(json_path):
    # 将当前json文件都合到一起形成news_inserted.json
    # "data"键对应的值(列表)是一条条新闻,是通过其他json文件中的"data"键获取的,包括上一次运行产生的news_inserted.json
    news_inserted = {}
    news_inserted["data"] =  []
    titles = []

    json_list = os.listdir(json_path)
    for filename in json_list:
        if not filename.endswith(".json"):
            continue
        with open(json_path + filename, 'r', encoding='utf-8') as f:
            data = json.load(f)["data"]
        news_inserted["data"].extend(data)
        for news in data:
            titles.append(news["title"])
        shutil.move(json_path + filename, json_path + "backup/" + filename)
    
    news_inserted["num"] = len(titles)
    if news_inserted["num"] > 0:
        with open("news_inserted.json", 'w', encoding="utf-8") as f:
            json.dump(news_inserted, f, ensure_ascii=False)

    print(f"已有{len(titles)}条新闻")
    return titles


def get_sentiment(Text):
    with open("../user.csv", "r") as f:
        reader = csv.reader(f)
        next(reader)
        for x in reader:
            AccessKeyId = x[1]
            AccessKeySecret = x[2]
    client = AcsClient(AccessKeyId, AccessKeySecret, "cn-hangzhou")
    request = GetSaChGeneralRequest.GetSaChGeneralRequest()
    request.set_Text(Text)
    request.set_ServiceCode("alinlp")
    response = client.do_action_with_exception(request)
    resp_obj = json.loads(response)
    data = resp_obj["Data"].replace("true", "True")
    data = ast.literal_eval(data)
    
    return data["result"]["sentiment"]   


if __name__ == "__main__":
	# 想加什么博物馆往字典里加就行
    keywords = {"故宫博物院": [], "首都博物馆": [], "中国科学技术馆": [], "中国地质博物馆": [], "中国人民革命军事博物馆": [],      
                "中国航空博物馆": [], "中国国家博物馆": [], "北京自然博物馆": [], "上海博物馆": [], "南京博物院": [],
                "北京鲁迅博物馆": [], "浙江省博物馆": [], "中国茶叶博物馆": []}
    JSON_PATH = "./"  # 默认所有操作均在当前目录
    titles = update_check(JSON_PATH)
    for keyword in keywords.keys():
        for curPage in range(1, 11): 
            origin_url = f"http://so.news.cn/getNews?keyword={keyword}&curPage={curPage}&sortField=0&searchFields=1&lang=cn"
            url_list = get_url_list(origin_url)
            if url_list is not None:
                keywords[keyword].extend(url_list)
        if len(keywords[keyword]) == 0:
            print(f"没有找到{keyword}的新闻  :(")
        else:
            print(f"共找到{len(keywords[keyword])}条关于{keyword}的新闻  :)")
            crawl_news(keywords[keyword], keyword, titles)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353
  • 354
  • 355
  • 356

(2)导入数据库

import os
import json
import mysql.connector


# 读取json文件
def load_json(json_path):
    # 合并各个json文件的内容后,要存入数据库的列表,忽略news_inserted.json
    news_to_insert = []

    json_list = os.listdir(json_path)
    for filename in json_list:
        if not filename.endswith(".json"):
            continue
        if filename == "news_inserted.json":
            with open(json_path + filename, 'r', encoding='utf-8') as f:
                num = json.load(f)["num"]
                print(f"已有{num}条数据")
            continue
        with open(json_path + filename, 'r', encoding='utf-8') as f:
            data = json.load(f)["data"]
            if data is None:
                continue
            for news in data:
                news_to_insert.append(tuple(news.values())[:-1])
    
    return news_to_insert


def insert_mysql(news_to_insert):
    print(f"预计插入{len(news_to_insert)}条数据。。。")
    if len(news_to_insert) == 0:
        print("没有新的数据要插入")
        return

    DATABASE = "MUSEUM"
    TABLE = "news"
    mydb = mysql.connector.connect(
        host = "localhost",
        user = "root",
        passwd = "123456",
        database = DATABASE
    )
    mycursor = mydb.cursor()
    sql = f"INSERT INTO {TABLE} (museum, time, type, content, photo, source) VALUES (%s, %s, %s, %s, %s, %s)"
    val = news_to_insert
    mycursor.executemany(sql, val)
    mydb.commit()
    print(f"{mycursor.rowcount}条记录插入成功。。。")
    mycursor.close()

 
if __name__ == "__main__":
    json_path = "./"
    news_to_insert = load_json(json_path)
    insert_mysql(news_to_insert)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/628590
推荐阅读
相关标签
  

闽ICP备14008679号