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的主要内容,如果未能解决你的问题,请参考以下文章