python进行爬虫+数据处理+导入Mysql

Posted 人帅气质佳A

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python进行爬虫+数据处理+导入Mysql相关的知识,希望对你有一定的参考价值。

最近有个需求,爬取文章数据供大屏端使用。

菜鸡落泪,记录一下学习过程与踩过的坑

一、爬虫

我选择爬取的网站是云南省应急管理厅的数据url为:云南省应急管理厅 (yn.gov.cn),选取里安全生产的综合监管标题栏下的文章爬取如下:

 

导入所需要的函数库 后从创建列表用于存放数据如下:

'''导入相关库'''
from lxml import etree     #解析文档
import bs4
import requests            #获取网页
import pandas as pd        #保存文件
'''构造循环爬取网页'''
all_content = []          #内容
all_title = []             #爬取的标题存储在列表中
all_time = []              #爬取的时间存储在列表中
url = []                   #研究报告网页链接
href = []

然后设置用户代理,获取该目录页面的html超文本标记语言,定位到每篇文章标题

headers = 
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36'
    #构造头文件,这是模拟真人登录(ps:有缺失,请自己动手)
url1 = f'http://yjglt.yn.gov.cn/html/anquanshengchan/zonghejianguan/'#目标网页链接
res1 = requests.get(url1,headers=headers)#获取网页
soup = bs4.BeautifulSoup(res1.text,"html.parser")#解析
targets1 = soup.find_all("li",class_="list-group-item")#获取目标字段(ps:暂时叫它字段吧),见下面第一张图(图1,依次类推)
#print(len(targets1))
#print(targets1)

 

 接下来就是仔细观察到每篇文章的链接不同,有的以http开头,有的以html开头,用一个if条件判断将其区分开:

 

 

然后就是进入每篇文章的链接,爬取文章的标题、发布时间、文章内容保存于列表,xpath定位相关内容,值得一提的是下面只要时间不要出处,可将xpth中的span改为span[1]。

 

还有就是html开头的链接无效,需要将url补充完整如下:

如此便成功爬取到了数据,将时间列表规范一下,搭建DataFrame对象保存数据为csv文件,代码和文件截图如下:

#爬取的时间列表为双列表,此处用此操作转换为单列表
all_time = [item for sublist in all_time for item in sublist]
#创建DataFrame对象存放数据
data_raw = pd.DataFrame()
data_raw["puth_time"] = all_time
data_raw["title"] = all_title
data_raw["content"] = all_content
#生成CSV文件
data_raw.to_excel("安全生产.xls",index=False,encoding='gbk')#这里我就不放保存路径了,每个人的都不一样
print("安全生产保存成功!")

二、数据处理

爬取得到的数据不是很规范,前面的中括号和换行符特别影响心情,需要把它简单处理,后面的在页面端一般看不到,不做处理,这里我使用python列表切片法,爬取下来的列表切片后为空,查看字符串长度为2,这么多字这么长怎么可能为2?在保存为csv文件后再读取,发现字符串长度变正常了,比title字段,长度大概在90多,直接对字段title和content前面内容切片

#读取文件并将字段类型设置为字符型,如果不保存为CSV文件,许多中文内容字符串长度为2,不方便切片处理,保存之后字符串长度变长,蛮方便处理
data = pd.read_excel('安全生产.xls',dtype = 'str') 
#data.head()
#切片处理标题字段和内容字段,将前面的杂乱字符剔除,后面的和中间的多余字符没咋管
title_extra = []
content_extra = []
for i in data["title"]:
    #print(i[5:])
    title_extra.append(i[7:70])
for i in data["content"]:
    #print(i[8:])
    content_extra.append(i[8:])

切片后保存为新的csv文件。 

三、插入数据库

因为是小白,之前只接触过一次(抄室友代码),现在自己来入库也是比较曲折,在成功连接自己数据库的基础上,用游标自己写SQL插入多行数据,for循环+execute函数,失败!,直接用executemany函数一次插入多行,也是失败,报错大概意思是字符串占位符不太匹配,要么就是SQL有语法错误。卡了半天没解决,插入部分代码如下:

# 3). *********************插入多条数据****************************
try:
    info_1 =  all_date_and_resouce
    info_2 =  all_title
    info_3 =  all_content
    
    for i in all_title:
        print(i)
        insert_sqli = "insert into 舆情(title) values(i);"
        cur.execute(insert_sqli)
    
       insert_sqli_1 = "insert into 舆情(`time`) values(%s);"
       insert_sqli_2 = "insert into 舆情(title) values(%s);"
       insert_sqli_3 = "insert into 舆情('content') values(%s);"
       cur.executemany(insert_sqli_1, info_1)
       cur.executemany(insert_sqli_1, info_1)
       cur.executemany(insert_sqli_3, info_3)
except Exception as e:
    print("插入多条数据失败:", e)
else:
    # 如果是插入数据, 一定要提交数据, 不然数据库中找不到要插入的数据;
    conn.commit()
    print("插入多条数据成功;")

后来在博客看到一个方法,不用连上数据库手动写SQL,直接将DataFrame数据插入数据库,两行代码完全解决问题!!!

#读取处理后的数据,为导入mqsql做准备
data_final = pd.read_excel('安全生产_final.xls',dtype = 'str') 
data_final.head()
#导入相关库
from sqlalchemy import create_engine
#配置mqsql
engine = create_engine("mysql+pymysql://root:123@localhost:3306/db1?charset=utf8mb4")
#导入mysql数据库
data_final.to_sql(name="舆情1",con=engine,if_exists='replace',index=False,index_label=False)
print('插入数据库成功!')

看一下数据库

OK,插入成功!

四、一些思考 

1.爬取数据还得精准定位url,不然数据都找不到。

2.爬虫定位具体数据,re、bs4、xpath三种方式很灵活,用法也很多,处理得当更容易获取规范的数据

3.爬虫还得懂一部分前端知识,

4.python的数据类型,python的双重列表和列表数据提取也挺灵活,有时可以转换为DataFrame用pandas来处理。

5.python中的连接数据库写SQL类似Java的传统JDBC操作,有什么游标啥的,而后面python采用sqlalchemy函数库(第一次见这个东东)一句代码就将DataFrame数据直接插入,感觉比Java的Mybatis框架还NB,只能说我还是个弟弟。

五、存一下源码

'''导入相关库'''
from lxml import etree     #解析文档
import bs4
import requests            #获取网页
import pandas as pd        #保存文件
'''构造循环爬取网页'''
all_content = []          #内容
all_title = []             #爬取的标题存储在列表中
all_time = []              #爬取的时间存储在列表中
url = []                   #研究报告网页链接
href = []

headers = 
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36'
    #构造头文件,这是模拟真人登录(ps:有缺失,请自己动手)
url1 = f'http://yjglt.yn.gov.cn/html/anquanshengchan/zonghejianguan/'#目标网页链接
res1 = requests.get(url1,headers=headers)#获取网页
soup = bs4.BeautifulSoup(res1.text,"html.parser")#解析
targets1 = soup.find_all("li",class_="list-group-item")#获取目标字段(ps:暂时叫它字段吧),见下面第一张图(图1,依次类推)
#print(len(targets1))
#print(targets1)

#判断文章的URL是以html开头还是http开头,如果是以html开头则需要下文进行处理变为标准的URL,才能准确定位到文章
targets_html =[]
targets_http = []
for x in targets1:
    y = x.a["href"].startswith("/html")
    if y == True:
        targets_html.append(x)
    else:
        targets_http.append(x)
print("html为前缀的文章为:***********************************************************")
print(targets_html)
print("http为前缀的文章为:***********************************************************")
print(targets_http)

#解析文章的内容,通过xpath方法定位到文章的标题、发布时间、文章内容,从而进行爬取
for e in targets_http:
    h2=e.a["href"]#获取href里的内容
    res3 = requests.get(h2,headers=headers)#解析href的网页链接(即文本链接)
    root2 = etree.HTML(res3.text)#再次解析href链接里的内容
    '''接下来就是在里面获取内容,后面的步骤与上一篇文章的方法差不多,就不过多赘述啦'''     
    title1 = root2.xpath("/html/body/div[2]/div[2]/div[2]/div/div[1]/text()")
    #print(title)
    #提取span[1]就仅仅提取到时间,而没有提取到来源和出处
    date_and_resouce1= root2.xpath("//div[contains(@class,'info-container')]//div[contains(@class,'info-title')]//div[contains(@class,'report-subtitle detail-subtitle')]//span[1]//text()")     
    #source = root.xpath("//div[contains(@class,'content')]//div[@class='creab']//span//a//text()")
    #print(company)
    content3 = root2.xpath("//div[contains(@class,'info-container')]//div[contains(@class,'info-content')]//p//text()")
    #文章内容存在着分割,图片或者表格分割,他在HTML语言中分段存放,所以要将文章内容合并
    content4 = "".join(content3)
    #print(content2)
    #在定义好的总列表添加爬取到的的相关内容
    all_title.append(title1)
    all_time.append(date_and_resouce1)
    all_content.append(content3)
print("第一部分数据爬取完成!")
#html语言开头的URL不规范,此处在其前面添加'http://yjglt.yn.gov.cn/'方能精准定位,其余操作与http开头的url一样
for each in targets_html:
    hl=each.a["href"]#获取href里的内容
    res2 = requests.get('http://yjglt.yn.gov.cn/'+hl,headers=headers)#解析href的网页链接(即文本链接)见图2
    root = etree.HTML(res2.text)#再次解析href链接里的内容
    '''接下来就是在里面获取内容,后面的步骤与上一篇文章的方法差不多,就不过多赘述啦'''     
    title = root.xpath("/html/body/div[2]/div[2]/div[2]/div/div[1]/text()")
    #/html/body/div[2]/div[2]/div[2]/div/div[1]/text()
    #print(title)
    date_and_resouce= root.xpath("//div[contains(@class,'info-container')]//div[contains(@class,'info-title')]//div[contains(@class,'report-subtitle detail-subtitle')]//span[1]//text()")     
    #source = root.xpath("//div[contains(@class,'content')]//div[@class='creab']//span//a//text()")
    #print(company)
    content1 = root.xpath("//div[contains(@class,'info-container')]//div[contains(@class,'info-content')]//p//text()")
    content2 = "".join(content1)
    #print(content2)     
    all_title.append(title)
    all_time.append(date_and_resouce)
    all_content.append(content2)
#print(all_title)
#print(all_company)
print("第二部分数据爬取完成!")

#爬取的时间列表为双列表,此处用此操作转换为单列表
all_time = [item for sublist in all_time for item in sublist]
#创建DataFrame对象存放数据
data_raw = pd.DataFrame()
data_raw["puth_time"] = all_time
data_raw["title"] = all_title
data_raw["content"] = all_content
#生成CSV文件
data_raw.to_excel("安全生产.xls",index=False,encoding='gbk')#这里我就不放保存路径了,每个人的都不一样
print("安全生产保存成功!")

#读取文件并将字段类型设置为字符型,如果不保存为CSV文件,许多中文内容字符串长度为2,不方便切片处理,保存之后字符串长度变长,蛮方便处理
data = pd.read_excel('安全生产.xls',dtype = 'str') 
#data.head()
#切片处理标题字段和内容字段,将前面的杂乱字符剔除,后面的和中间的多余字符没咋管
title_extra = []
content_extra = []
for i in data["title"]:
    #print(i[5:])
    title_extra.append(i[7:70])
for i in data["content"]:
    #print(i[8:])
    content_extra.append(i[8:])
#content_extra
#将处理后的数据保存为CSV文件
data_raw["puth_time"] = all_time
data_raw["title"] = title_extra
data_raw["content"] = content_extra
data_raw.to_excel("安全生产_final.xls",index=False,encoding='gbk')#这里我就不放保存路径了,每个人的都不一样
print("安全生产_final保存成功!")

#读取处理后的数据,为导入mqsql做准备
data_final = pd.read_excel('安全生产_final.xls',dtype = 'str') 
data_final.head()
#导入相关库
from sqlalchemy import create_engine
#配置mqsql
engine = create_engine("mysql+pymysql://root:123@localhost:3306/db1?charset=utf8mb4")
#导入mysql数据库
data_final.to_sql(name="舆情1",con=engine,if_exists='replace',index=False,index_label=False)
print('插入数据库成功!')

python2.7 爬虫_爬取小说盗墓笔记章节及URL并导入MySQL数据库_20161201

1、爬取页面 http://www.quanshu.net/book/9/9055/

2、用到模块urllib(网页下载),re正则匹配取得title及titleurl,urlparse(拼接完整url),MySQLdb(导入MySQL) 数据库

3、for 循环遍历列表 取得盗墓笔记章节title 和 titleurl

4、try except 异常处理

5、python 代码

#-*-coding: utf-8 -*-
import urllib
import re
import urlparse
import MySQLdb
rooturl=‘http://www.quanshu.net/book/9/9055/‘
def getlist(url):
    html=urllib.urlopen(url).read()
    html=html.decode(‘gb2312‘).encode(‘utf-8‘)
    reg=r‘<li><a href="(.*?)" title=".*?">(.*?)</a></li>‘
    return re.findall(reg,html)
try:
    conn = MySQLdb.connect(host=‘localhost‘, user=‘root‘, passwd=‘123456‘, db=‘local_db‘, port=3306, charset=‘utf8‘)
    with conn:
        cursor = conn.cursor()
        drop_table_sql=‘DROP  TABLE IF EXISTS daomubiji‘
        cursor.execute(drop_table_sql)
        conn.commit()
        create_table_sql = ‘‘‘
           CREATE TABLE daomubiji (
           ID INT(11),
           title VARCHAR(255),
           titleurl VARCHAR(255)
           )ENGINE=INNODB DEFAULT CHARSET=utf8
        ‘‘‘
        cursor.execute(create_table_sql)
        conn.commit()
        urllist = getlist(rooturl)
        #href属性取得的url不完整 仅取出了完整url的右半段 因此下面for循环变量名起名righturl
        ID=0
        for righturl in urllist:
            title = righturl[1]
            newurl = righturl[0]
            #urlparse 模块的urlparse.urljoin方法将righturl 按照rooturl格式拼接成完整url
            titleurl = urlparse.urljoin(rooturl, newurl)
            ID+=1
            print ID,title, titleurl
            cursor.execute("INSERT INTO  daomubiji values(%s,%s,%s)", (ID,title, titleurl))
            conn.commit()
        print "输入了"+ str(ID) +"条数据"
except MySQLdb.Error:
    print "连接失败!"

代码执行情况:

技术分享

6、MySQL数据库查询是否导入成功

SELECT * FROM daomubiji

  技术分享

 7、执行成功

以上是关于python进行爬虫+数据处理+导入Mysql的主要内容,如果未能解决你的问题,请参考以下文章

python爬虫爬下来的数据怎么导入到MySQL

python2.7 爬虫_爬取小说盗墓笔记章节及URL并导入MySQL数据库_20161201

python连接mysql并写入数据(简单爬虫)

Python爬虫学习-简单爬取网页数据

如何利用Python进行基础自动点击爬虫

[python爬虫] Selenium爬取内容并存储至MySQL数据库