数据采集与预处理期末复习
一、概述
1.数据抓取
也称为网络爬虫,是指从网上获取数据,并将获取的数据转化为结构化数据,最终将数据存储到本地计算机或数据库的一种技术。
2.数据预处理
分为数据清洗、数据集成、数据转化、数据规约四个环节。
3.数据类型
结构化数据:又称行数据,是由二维表结构来逻辑表达和实现的数据。
非结构化数据:指数据结构不规则或不完整,没有预定义的数据模型,不方便用数据库二维表来存储和管理的数据,如文本文档、图片、视频、音频等。
半结构化数据:主要指的是一种结构变化很大的结构化数据。
4.爬虫分类
通用网络爬虫、聚焦网络爬虫、增量式网络爬虫和深层次网络爬虫。
二、静态网页爬取
1.编写爬虫三步骤
网页数据获取:使用通用函数get_html提取目标页面的HTML内容。
数据解析:使用BeautifulSoup解析器或Xpath解析器进行元素定位、结点数据提取。
数据存储:通过Python文件csv、excel、text等操作或数据库来保存数据。
2.Requests库发送GET请求/POST请求
# 导包
import requests
# head设置用户代理
head={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.82 Safari/537.36"}
r=requests.get("http://www.baidu.com",headers=head,timeout=5) # params为参数名,timeout为等待时间
# r=requests.post("http://www.baidu.com",headers=head,timeout=5) # params为参数名,timeout为等待时间
r.encoding='utf-8' # 设置编码格式为utf-8
# r.raise_for_status() # 根据返回的内容猜测编码格式
print(r.text)
三、网页解析
1.BeautifulSoup解析器
shuju1=BeautifulSoup(html,"lxml") # 使用lxml解析器
shuju2=shuju1.select("#comments .comment-item") # 定位标签,获取标签内容
shuju=[]
for sj in shuju2:
sjs=[
sj.select(".comment-info a")[0].text, # 爬取文本属性
sj.select(".comment-time")[0].text, # 爬取文本属性
sj.select(".comment-content")[0].text # 爬取文本属性
sj.select(".pc_temp_songname")[0].text.split("-")[0], # 爬取文本属性并切片
sj.select(".pc_temp_songname")[0].text.split("-")[1], # 爬取文本属性并切片
sj.select("a")[0].attrs["href"] # 爬取链接属性
]
shuju.append(sjs) # 将sjs列表内容添加至shuju列表中
2.Xpath解析器
shuju1=etree.HTML(html) # 使用lxml解析器
shuju2=shuju1.xpath("//div[@class='list max-1152 clearfix']/a") # 定位标签
shuju=[]
for sj in shuju2:
x1=sj.xpath("p[1]/text()")[0] # 爬取课程名称
x2="http:"+sj.xpath("@href")[0] # 爬取课程链接
x3="https:"+sj.xpath("div/@style")[0].replace("background-image: url('","").strip("')") # 爬取图片链接
x4=sj.xpath("p[2]/text()")[0].split("·")[1].strip("人报名") # 爬取学习人数,只取数字
shuju.append([x1,x2,x3,x4])
注1:使用属性查找元素一般格式为“标签名[@属性名='属性值']”也可以使用通配符*。
注2:使用Xpath解析器时可以把多个类名当成一个整体,但必须保证class属性值与网页保持一致,包括空格。
四、数据存储
(一)文本存储
如果需要写入二进制数据,需要增加参数b,写入二进制的读写模式包括wb、wb+、rb、rb+、ab、ab+等。
1.保存text文件
title="测试使用数据文本\n" # 初始化字符串参数title
with open("D:\\title.text","a+",encoding="utf-8")as f: # 创建文件,存储位置+存储方式+编码方式
f.write(title) # 写入数据
2.保存csv文件
import csv # 存储数据
item=[["测试存储数据1","字段","字段"],["测试存储数据2","字段","字段"]]
path="数据.csv"
with open(path,"w+",newline="",encoding="utf-8-sig")as f: # 创建utf-8编码文件
xieru=csv.writer(f) # 创建写入对象
xieru.writerows(item) # 批量写入多行数据
# xieru.writerow(item) # 写入一维数据
3.保存excel文件
法一:将csv改为excel
另:只需将to_csv改为to_excel。
(二)数据库存储
def cunchu(sql,shuj,**parm): # 使用MySQL储存网页数据
try:
lianjie=pymysql.connect(**parm) # 创建数据库链接
youbiao=lianjie.cursor() # 获取游标对象
youbiao.executemany(sql,shuj) # 执行多条sql
lianjie.commit() # 提交事务
except Exception as error:
lianjie.rollback() # 事务回滚
print(error)
finally:
youbiao.close() # 关闭游标
lianjie.close() # 关闭链接
if __name__=="__main__": # 主函数
html=huoqu(url)
shuju=jiexi(html)
parms={
"host":"localhost", # 主机
"user":"root", # 用户
"password":"root", # 密码
"db":"jupyter", # 数据库名
"charset":"utf8" # 字符集
}
sql="insert into shiyan4(keming,kelian,tulian,renshu)values(%s,%s,%s,%s)" # SQL语句
cunchu(sql,shuju,**parms) # 储存到数据库中
五、动态网页爬取
动态网页爬取一般分为逆向分析法(json库)和模拟法(Selenium库)。
1.json库爬取网络数据
2.Selenium库爬取网页数据
强制等待:时间到才跳转。
(如:time.sleep(3))
隐式等待:网页加载成功或超时才跳转。
(如:wd.implicitly_wait(3))
显式等待:指定元素加载成功或超时才跳转,设定时间内,每隔参数时间检查一次。
(如:WebDriverWait(wd,3,0.3).until(lambda x:x.find_element_by_id("login_button")).click() # 点击授权登录)
import pymysql # 导入数据库
from selenium import webdriver
from selenium.webdriver import Chrome,ChromeOptions
from selenium.webdriver.support.wait import WebDriverWait # 显示等待
zshuju=[]
# opt=ChromeOptions() # 创建Chrome参数对象
# opt.headless=True # 将Chrome设置为无界面模式
# wd=Chrome(options=opt,executable_path="C:/软件/Chrome驱动器/chromedriver.exe") # 获取无界面浏览器驱动
wd=webdriver.Chrome("C:/软件/Chrome驱动器/chromedriver.exe") # 获取浏览器驱动
wd.get("https://www.ptpress.com.cn/shopping/index")
for i in range(1,17):
a="//div[@class='tabs']/span[{}]".format(i)
# WebDriverWait(wd,30,0.3).until(lambda x:x.find_element_by_xpath(a)).click() # 显式等待,点击不同的分类
time.sleep(5) # 强制等待5s
wb.find_element_by_xpath(a).click() # 点击不同的分类
html=wd.page_source # 获取网页HTML
for j in range(1,19):
xp1="//*[@id='hotBook']/div[2]/div[2]/div[{}]/div/a/p".format(j)
xp2="//*[@id='hotBook']/div[2]/div[2]/div[{}]/div/a/div/img".format(j)
x1=wd.find_element_by_xpath(xp1).text # 爬取图书名称
x2=wd.find_element_by_xpath(xp2).get_attribute("src") # 爬取图片链接
x3=wd.find_element_by_xpath(xp2).get_attribute("src")[42:59] # 爬取图书ID
zshuju.append([x1,x2,x3])
wd.close() # 关闭浏览器
wd.switch_to.frame("tcaptcha_iframe") # 打开当前页面的子窗口
wd.find_element_by_id("login_button").click() # 完成点击操作
wd.find_element_by_id("u").send_keys(qh) # 完成自动输入操作
wd.close() # 关闭当前窗口
wd.quit() # 关闭所有窗口

六、Scrapy框架
1.创建爬虫项目
scrapy startproject 项目名
2.生成爬虫文件
cd 项目名
scrapy genspider 爬虫文件名 网络地址域名
3.定义数据容器
找到项目中的items.py文件
去掉pass,添加数据项
loupan = scrapy.Field() # 楼盘
dizhi = scrapy.Field() # 地址
danjia = scrapy.Field() # 单价
zongjia = scrapy.Field() # 总价
... ...
4.修改配置文件
常用:设置数据库配置文件、设置用户代理、设置延迟下载、Cookies、自动限速扩展等等。
其它:下载器中间件、随机用户代理、随机IP代理等等。
5.定义数据库
import pymysql
def __init__(self):
# 读取settings.py中的数据项
host = settings.MySql_host
port = settings.MySql_port
dbname = settings.MySql_name
user = settings.MySql_user
pwd = settings.MySql_password
# 创建数据库连接
self.db_conn = pymysql.connect(host=host, port=port, db=dbname, user=user, password=port, passwd=pwd)
# 打开游标
self.db_cur = self.db_conn.cursor()
values = (
item['maidian'],
item['loupan'],
item['loupandizhi'],
)
# SQL语句,数据部分用占位符%s代替
sql = "insert into zhufangxinxi(maidian,loupan,loupandizhi)values(s%,s%,s%)"
self.db_cur.execute(sql, values) # 执行SQL语句
self.db_conn.commit() # 提交事务
return item
self.db_cur.close() # 关闭游标
self.db_conn.close() # 关闭数据库连接
6.编写爬虫文件
... ...
7.运行爬虫文件
命令:scrapy crawl 爬虫文件名
或输出文件命令:scrapy crawl 爬虫文件名 -o 爬虫文件名.csv
七、数据预处理
pandas基础数据结构包括Series和DataFrame,Series是一维数组、DataFrame类似二维数组。
data = pd.read_excel('文件名',index_col='索引名',sep='分隔符') # 读出excel数据,指定index_col索引,以sep为分隔
ddd=pd.to_excel('文件名',columns=['字段1','字段2'],...) # 写入excel文件,写入该字段1、2、...
data.head() # 读取前5行
data.head(n) # 读取前n行
data.sample() # 随机读取五行
data[['字段1','字段2',...]] # 读取多列
data['字段名'] # 读取一列
data[1,m,['字段1','字段2',...,'字段n']] # 读取m行n列
data.info() # 查询行列数及列是否为空等信息
data.describe() # 查看统计性描述信息
df.set_index('字段名') # 以该列为索引进行排序
df.drop(['字段1','字段2',...,'字段n'],axis=1) # 删除这n列
df.drop(['字段1','字段2',...,'字段n'],axis=0) # 删除这n行
df.sort_values('字段名',ascending=False) # 按该列降序排序
df.sort_values('字段名') # 按该列升序排序,ascending=True为默认值
df3.merge(df1,df2,on='索引名') # 按索引名求交集
df3.merge(df1,df2,how='索引名') # 按索引名求并集
df2.join(df1) # 将df1按列加入df2
df1=df[0:5]['字段1'] # 5行1列
df2=df[5:20]['字段1'] # 15行1列
df3=pd.concat([df1,df2]) # 按行合并,默认axis=0
data.fillna(method='ffill') # 向后填充,或pad
data.fillna(method='bfill') # 向前填充
data.fillna(x) # 填充固定值x
data2.fillna(data1.mean()) # 填充该列的平均值
data1.dropan(axis=0) # 删除空的行
data1.dropan(axis=1) # 删除空的列
data6=data['...']<1500 # 取列