实训小结:Python入门到爬虫
Python实训
一、基础入门
1. 行业
2. 搭建开发环境
1,安装Python3.6版本
一定要勾选将python所在环境添加到path
2,安装开发工具PyCharm
3.如何使用PyCharm创建一个Python项目
1,选择create new project
2,修改项目存储路径,路径的最后一个为项目名称
4. 如何在Pycharm创建的Python项目中,创建Python文件
1,选中项目
2,点击鼠标右键,选择new
3,选择python file
5. 代码
1,注释
单行注释:#xxxx
多行注释:'''xxxx'''
2,输出与输入
输出:print("要输出内容")
输入:输入的内容 = input("提示字")
3,变量
Python中之间写变量名就好
变量名要求:
小驼峰
见名知意
不能使用数字,特殊符号开头
4,数据类型
可以通过type获取变量的数据类型
如:
num = 10
type(num)
5,数据类型转换
str()
int()
float()
chr()
6,运算
算数运算
+,-,*,/,%
逻辑运算
<,>,<=,>=,==,!=
and or not
赋值运算
=,+=,-=,*=,/=,%=
7,分支语句
Python中分支语句为if
语法格式如下:
if(条件表达式1):
当条件表达式1为真时,执行此处代码
elif(条件表达式2):
当条件表达式2为真时,执行此处代码
elif(条件表达式3)
当条件表达式3为真时,执行此处代码
...
else:
当以上条件都为假时,执行此次代码
8,循环语句
Python中循环语句:while
语法格式参考Java
9,遍历
Python中的遍历for
类似语句Java的增强for循环
10,随机数
1,导包
2,获取随机数
二、字符串
1. 字符串
str
2. 数据存储
-
临时存储:随着程序的关闭而消失
变量
类对象
列表等
java中临时存储
数组
对象
list
set
map
python中临时存储
变量
对象
元组:类似于java中的数组,使用小括号定义,数据不可变
列表:类似于java中ArraryList,使用中括号定义,内容可变
字典:类似于java中map,使用大括号定义,键值对应。
-
持久化存储:不会随着程序而消失
文件
数据库
网络存储
三、面向对象
1.概念
面向对象是一种思维
与其对立的是面向过程将大象装进冰箱里需要几步
开门 装 关门
面向对象思维考虑
1.事物中存在哪些对象
2.考虑对象与对象的关系
对象:一种真实的事物
类:将一类具有相同属性行为的形成的概念
真实生活:先有对象后有类
代码中:需要类才可创建对象
子类->父类 ,没有风险
父类->子类 存在类型转换异常继承多态封装
2.代码
__init__ 相当于java的构造方法
__变量名 # 定义私有属性,私有属性在类外部无法直接进行访问
self #类似于java的构造函数,self类似于java的this
class C(A,B)
#多继承# 需要注意圆括号中父类的顺序,若是父类中有相同的方法名,而在子类使用时未指定,
# python从左至右搜索 即方法在子类中未找到时,从左到右查找父类中是否包含方法。
3.方法(函数)
-
java方法
访问权限修饰符[修饰符] 返回类型 方法名([形参列表]){ 方法体 return; }
-
java方法使用
方法名([实参列表])
-
python方法
def 方法名([形参列表]):
方法体
return;
-
python方法的使用
方法名([实参列表])
-
python中实参可以按照形参的顺序进行传输
-
python有默认赋值的形参可以不进行传值
-
有返回值类型的方法可以使用变量进行接收
-
可以有多个返回值接收
-
好处
方法作用:
1.封装代码
方法的好处: 1.保护内部代码 2.方便外部调用 3.降低代码耦合度
四、文件I/O、邮件、GUI
1,文件操作
os:导包
判断文件是否存在
os.path.exists(文件路径)
当返回值为true时,表示文件存在,反之不存在
如何创建多级文件夹
os.makedirs(“文件夹路径”)
每个单词之间的/表示为下级文件夹
如:a/b/c,创建a文件夹,在a文件夹下,创建b文件夹,在b文件下,创建c文件夹
open:打开文件
文件对象 = open(文件路径,模式,编码格式)
文件路径:
相对路径
相对于当前py文件所在的位置
../:上一层
./:当前路径下
/xx:下一层
绝对路径
文件在电脑中的位置:如c://a/b/test.txt
如:文件对象 = open(“文件所在路径”,mode=“模式”,encoding=“utf-8”)
模式:
w:写,如果文件不存在,可以帮助我们创建文件,如果文件已经存在,删除后再创建文件
r:读
a:追加,如果文件不存在,可以帮助我们创建文件,如果文件已经存在,使用当前文件
文件操作
读:文件对象.write(写入的内容)
文件对象.write(写入的内容)
写:文件对象.read()读取文件中所有内容
读取到的内容 = 文件对象.read()
关闭:文件对象.close()
文件对象.close()
2,time
time.sleep(阻塞时间单位秒)
获取当前时间time.time()
3,邮件发送
需要的包
from email.mime.text import MIMEText
import smptlib
步骤
1,准备需要的数据
发送者昵称
发送者账号
发送者账号授权码
接受者邮箱
邮件标题
邮件正文
2,组装邮件:MIMEText
使用
发送人昵称
标题
正文
from email.mime.text import MIMEText
msg = MIMEText(正文)
msg["From"] = 发送人昵称
msg["subject"] = 标题
3,登录邮箱smtplib
1,获取客户端
import smtplib
client = smtplib.SMTP("smtp.qq.com",25)
2,登录
发送人邮箱
发送人授权码
client.login(发送人邮箱,发送人授权码)
4,发送邮件
发送人邮箱
收件人邮箱
邮件
client.sendmail(发送人邮箱,收件人邮箱,msg=msg.as_string())
5,退出登录
client.quit()
4,可视化
类似于Java中的GUI
所需包:
tkinter
窗口
创建窗口
window=tkinter.Tk()
设置窗口
设置窗口标题
设置窗口大小
设置窗口宽高是否可变
显示窗口
mainloop()
组件
文本:Lable
属性:text:展示的文本
输入框:Entry
属性:width:宽度
按钮:Button
属性:command:点击后执行的方法,text:展示的文本 注意:所有组件添加完成后,都需要显示 pack
五、前端网页
为什么学?
因为爬虫需要从网页中获取数据,所以需要了解网页
如果后期制作flask项目,需要前端展示,也需要会前端网页
代码学习路径
-
搭建环境
-
安装开发工具
-
创建项目
项目结构
css:存放css代码文件
img:存放项目中使用的图片文件,注意网页支持gif图
js:存放js代码文件
index.html:项目自带的网页文件
注意:一个项目中,可以有多个网页文件 -
编写代码
1.Html
标签格式
<标签名 ></标签名>
如:
<span></span>
<p></p>
<h1></h1>
<ul></ul>
<li></li>
<a></a>
....
可以容纳别的标签
<开始标签 属性区>内容区</结束标签>
<标签名 />
如:
<img />
<meta />
<br />
<hr />
称为最终标签,不能给其中嵌套别的标签
<标签名 属性区 />
所有标签都有id与class属性
**id:类似于人的身份证号,一个网页中id的值不允许重复**
**class:类似于对标签进行分类,值可以重复**
**所有标签都可以设置点击事件**
标签:
文本
span:文本标签,新的
font:文本标签,旧的
h1~h6:标题标签
p:段落
a:超链接
属性:href
作用:
跳转外部网址
跳转内部网址
跳转当前网页中指定区域
图片
img:图片展示标签
属性:src(值为图片所在地址)
注意:支持gif图
输入
input:输入
属性:
type
值(系统提供的,不能自定义)
text:文本输入(默认)
password:密码输入
button:按钮
radio:单选
checkbox:多选
value
值(自定义)
当type类型为text或password时,该属性值为输入框中的输入内容
当type类型为button时,该属性值为按钮上展示的内容
当type类型为radio或checkbox时,表示该按钮对应的值
name:
值(自定义)
当type类型为radio或checkbox时,name属性值相同则为一组
媒体
audio:音频
src:资源文件所在位置
video:视频
其他
br:换行
hr:水平分割线
ul:无序列表
li:列表子项
ol:有序列表
li:列表子项
select:选择器
option:子项
div:块
2.CSS(层叠样式表):
作用:美化,移动html标签
1,在哪里书写css代码
方案1:(不建议使用)
在标签的style属性中书写(内联样式)
方案2:(新手使用)
在head标签中书写style标签,
在style标签书写css代码
方案3:(熟练后使用)
在css文件中书写,
通过link标签引入到需要的html文件中
2,如何在css中寻找html标签?
通过选择器进行寻找
常用的选择器有?
id选择器 #名
class选择器 .名
标签选择器 p,a,div...
统配选择器 *{}
3,如果多个选择器,对同一个标签设置样式,听谁的(选择器权重)
选择器优先级相同时:
谁后写,听谁的
选择器优先级不同时:
听选择器优先级高的
选择器优先级
统配选择器 < 标签选择器 < class选择器 < id选择器 < 内联样式
4,可以美化什么?
*文字
文字大小 font-size
字体 font-family
字体样式 font-style
笔画粗细 font-weight
颜色 color
/**
* 颜色
* 系统定义的颜色
* 六位调色法
* #红绿蓝
* rgb
* rgba
* 光的三原色
* 红绿蓝
* 每个颜色的取值:0~255 十六进制00~FF
*/
/*color: #009900;*/
/*color: rgb(0,0,255);*/
/**
* a为透明度
* 1,不透明
* 0,全透明
*/
rgba(0,0,0,0.5);
行高 line-height
下划线 text-decoration:underline
*背景
背景颜色 background-color
背景图片 background-image:url("") ;
背景大小 background-size
/**
* 背景大小
* 1参:背景宽度 可以使用px,也可以%
* 2参:背景高度 可以使用px,也可以%
*/
背景是否平铺 background-repeat
/**
* 背景是否平铺
* no-repeat:不平铺
* repeat:平铺(默认)
*/
背景位置 background-position
/**
* 背景位置
* 1参:左右
* 左:left
* 右:right
* 中:center
* 2参:上下
* 上:top
* 下:bottom
* 中:center
*/
*大小
宽高 width height
内边距 padding 上右下左
外边距 margin 上右下左
边框 border,border-radius,border-top-left-radius
盒子模型分类 div ie盒子:box-sizing:border-box
*计算
/**
* 标准盒子组件占地
* 组件占地宽/高 = 宽/高+左右/上下内边距 +左右/上下边框 + 左右/上下外边距
* IE盒子组件占地:ie盒子计算中不减外边距
* 组件占地宽/高 = 宽/高+左右/上下外边距
*/
*位置
定位 position
相对定位 relative
相对定位元素的定位是相对其正常位置。
绝对定位 absolute
绝对定位的元素的位置相对于最近的已定 位父元素,如果元素没有已定位的父元 素,那么它的位置相对于<html>:
浏览器窗口定位 fixed
元素的位置相对于浏览器窗口是固定位置
居中
margin:上下的外边距 左右的外边距
auto:自适应
注意:组件必须是块元素
好处:不会影响别的标签位置
定位居中
left:%50
margin-left:-(width/2)px;
浮动
层级: z-index
左浮动 float:left
右浮动 float:right
清理浮动导致的空间塌陷 clear
*阴影
box-shadow:x y 阴影宽度 阴影颜色
*动画
*过渡
5,标签分为三类:
*行内元素
设置宽高无效,内容多宽,组件多宽:span,a
*行内块元素
设置宽高有效,不独占一行:input,img等
*块元素
设置宽高有效,独占一行:p,div,li,h1~h6d等
*如何修改标签元素类型
display属性
hidden可以隐藏某个元素,占位
none 隐藏元素,不占位
block:块元素
inline-block:行内块元素
inline:行内元素
六、Python爬虫
1.静态爬取
-
#网络请求的包:from urllib.request import Request, urlopen
#解压或压缩数据:import gzip
#https网址协议验签:import ssl#将数据转换为html格式:from lxml import etree
from urllib.request import Request, urlopen#网络请求的包
import gzip#解压或压缩数据
import ssl#https网址协议验签
from lxml import etree
if __name__ == '__main__':
# https协议验签
ssl._create_default_https_context = ssl._create_unverified_context;
path="https://www.biqooge.com/0_3/5372509.html";
headers={
"user-agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36 Edg/91.0.864.67",
"accept-encoding":"gzip"
};
#封装请求
req=Request(url=path,headers=headers);
#打开连接
conn = urlopen(req);
#判断连接是否成功,响应码是否为200
if conn.code == 200:
#获取后台数据
data = conn.read();
#判断是否为压缩格式
isGzip=conn.headers.get("content-encoding");
print(isGzip);
if isGzip=="gzip":
#解压数据
data=gzip.decompress(data);
#改变数据的编码格式
data=data.decode(encoding="gbk");
#解析数据
#解析1. 将数据转换为html格式
html=etree.HTML(data);
#获取章节名称,,准备xpath
titleXpath="//div[@class='bookname']/h1/text()";
titleTag=html.xpath(titleXpath);
print(html)
if len(titleTag)>0:
print(titleTag[0])
textXpath="//div[@id='content']/text()";
textTag=html.xpath(textXpath);
text="".join(textTag);
text=text.split();
text="\n".join(text);
print(text);
#存入本地
file=open(file="%s.txt"%(titleTag[0]),mode="a",encoding="utf-8");
file.write(titleTag[0]+"\n");
file.write(text);
file.close();
pass
else:
print("连接失败");
- 爬取目录,然后进入具体列表项爬
from urllib.request import Request, urlopen#网络请求的包
import gzip#解压或压缩数据
from lxml import etree
import demo01_爬虫 as pc
import time
import random
paths={}
def dowmload():
path = "https://www.biqooge.com/0_3/";
headers = {
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36 Edg/91.0.864.67",
"accept-encoding": "gzip"
};
# 封装请求
req = Request(url=path, headers=headers);
# 打开连接
conn = urlopen(req);
# 判断连接是否成功
if conn.code == 200:
# 获取后台数据
data = conn.read();
# 判断是否为压缩数据格式
isGzip = conn.headers.get("content-encoding");
print(isGzip);
if isGzip == "gzip":
# 压缩数据
data = gzip.decompress(data);
# 改变数据的编码格式
data = data.decode(encoding="gbk");
# 解析数据
# 解析1. 将数据转换为html格式
html = etree.HTML(data);
# 获取a标签的位置
aXpath = "//div[@id='list']/dl/dd/a";
aTag = html.xpath(aXpath);
print(aTag);
n = 5;
for a in aTag:
if n <= 0:
break;
itemPath = a.xpath("./@href");
itemName = a.xpath("./text()");
tt = random.randint(1, 4);
time.sleep(tt);
if len(itemPath) > 0 and len(itemName) > 0:
print(itemName[0], "https://www.biqooge.com" + itemPath[0]);
paths[itemName[0]]="https://www.biqooge.com" + itemPath[0];
n-=1;
pass
else:
print("连接失败");
if __name__ == '__main__':
dowmload();
keys=paths.keys();
for path in keys:
pc.main(paths[path]);
2.资源下载(图片、文件、视频)
- 图片获取
'''
网络请求的包
请求:Request
打开网址:urlopen
下载文件:urlretrieve urlretrieve(url="图片路径",filename="文件存储路径")
'''
from urllib.request import Request,urlopen,urlretrieve #urlretrieve(url="图片路径",filename="文件存储路径")
#用于解压数据 etree.Html(data)
from lxml import etree
#解压或者压缩数据 gzip.decompress()
import gzip
#https的网址进行验签使用
import ssl
#文件操作
import os
if __name__ == '__main__':
#验签
ssl._create_default_https_context = ssl._create_unverified_context;
#请求地址
path="https://www.baidu.com";
#请求头
headers={
"user-agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36 Edg/91.0.864.67",
"accept-encoding":"gzip"
}
#封装请求
req = Request(url=path,headers=headers);
# 打开连接
conn = urlopen(req);
#判断是否成功
if conn.code==200:
#读取服务器返回数据
data= conn.read();
#因为下载是压缩格式,需要解压
data = gzip.decompress(data);
#因为中文乱码,所以需要将编码格式改为网站的编码
data = data.decode(encoding="utf-8");
#解析
#转为html格式
html = etree.HTML(data);
#准备要获取的数据的xpath
imgTag= "//img[@id='s_lg_img']/@src";
#开始解析获取数据
imgs = html.xpath(imgTag);
#获取地址并完善
if len(imgs)>0:
imgPath = "https:"+imgs[0];
print(imgs);
#判断文件夹是否存在
if not os.path.exists("./img"):
#不存在就创建
os.makedirs("./img");
#下载
urlretrieve(url=imgPath,filename="./img/bd.png");
pass
else:
print("连接失败!");
3.动态资源获取
-
动态百度图爬取
#谷歌浏览器包 from selenium.webdriver import Chrome from urllib.request import urlretrieve # import time #百度图 import os if __name__ == '__main__': #加载驱动 #chrom = Chrom("驱动地址") chrom = Chrome("./chromedriver.exe"); #发起请求 chrom.get(url="https://image.baidu.com/search/index?tn=baiduimage&ipn=r&ct=201326592&cl=2&lm=-1&st=-1&fm=index&fr=&hs=0&xthttps=111110&sf=1&fmq=&pv=&ic=0&nc=1&z=&se=1&showtab=0&fb=0&width=&height=&face=0&istype=2&ie=utf-8&word=%E9%A3%8E%E6%99%AF&oq=%E9%A3%8E%E6%99%AF&rsp=-1"); #阻塞程序一段时间,让浏览器加载动态数据 # time.sleep(10); #获取class属性值为xxx # find_elements_by_class_name:通过class的属性值获取对应的标签 # find_element_by_id:通过标签的id获取标签 # find_elements_by_tag_name:通过标签名获取标签 imgs=chrom.find_elements_by_class_name("main_img"); #遍历数据 num=0; for img in imgs: # get_attribute:获取指定属性的属性值 # 获取到的标签.text:获取标签属性区的内容 #获取img里面的src imgPath=img.get_attribute("src"); print(imgPath); #保存本地 if not os.path.exists("./img"): os.makedirs("./img"); num+=1; #下载到本地 urlretrieve(url=imgPath,filename="./img/%d.jpg"%(num)); print(imgs); #退出浏览器 chrom.quit();
4. 爬取数据存入数据库
-
存入数据库
from urllib.request import Request,urlopen import ssl import gzip from lxml import etree #python操作mysql所用的包 #import pymysql def getData(path,headers,encoding): ssl._create_default_https_context = ssl._create_unverified_context req = Request(url=path,headers=headers) conn = urlopen(req) if conn.code == 200: data = conn.read() if conn.headers.get("Content-Encoding") == "gzip": data = gzip.decompress(data) data = data.decode(encoding=encoding) return data pass else: print("错误码:",conn.code) return "" pass ''' 数据库操作 导包 pymysql ''' #python操作mysql所用的包 import pymysql def saveBook(bookName,bookPath): #获取数据库连接对象 ''' host:连接的数据库所在的地址ip port:端口号 user:账号 password:密码 database=数据库名 charset=编码格式 ''' conn = pymysql.connect(host="127.0.0.1",port=3306,user="root", password="mysql",database="test",charset="utf8"); #获取游标,执行sql cursor = conn.cursor(); sql = "insert into books (b_name,b_path) values('%s','%s')"%(bookName,bookPath); #执行sql ''' 如果sql为查询语句,返回为查询结果集; 如果为增删改,返回为受影响行数 ''' result=cursor.execute(sql); if result<1: print("插入失败!"); else: #如果对数据库进行了更改就需要进行提交 conn.commit(); #关闭数据库 cursor.close() conn.close() if __name__ == '__main__': path="https://www.xbiquge.la/xiaoshuodaquan/"; headers={ "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36", "Accept-Encoding":"gzip" }; booksData=getData(path=path,headers=headers,encoding="utf-8"); bookshtml = etree.HTML(booksData); booksXpath="//div[@id='main']/div[@class='novellist']/ul/li/a"; books_a = bookshtml.xpath(booksXpath); for book_a in books_a: bookName = book_a.xpath("./text()"); bookPath = book_a.xpath("./@href"); # print("%s--%s"%(bookName[0],bookPath[0])); saveBook(bookName[0],bookPath[0]); print(booksData);
-
读取数据库
#python操作mysql所用的包 #import pymysql class Book: def __init__(self,id,name,path): self.id=id; self.name=name; self.path=path; def __str__(self): return ("id:%d name:%s path:%s"%(self,id,self.name,self.path)); ''' 数据库操作 导包 pymysql ''' #python操作mysql所用的包 import pymysql def getBooks(): list=[]; # 获取数据库连接对象 conn = pymysql.connect(host="127.0.0.1", port=3306, user="root", password="mysql", database="test", charset="utf8"); # 获取游标,执行sql cursor = conn.cursor(); sql = "select * from books"; # 执行sql ''' 如果sql为查询语句,返回为查询结果集; 如果为增删改,返回为受影响行数 ''' result = cursor.execute(sql); #fetchall获得查询结果元组 result = cursor.fetchall(); for book in result: id = book[0]; name = book[1]; path = book[2]; b=Book(id=id,name=name,path=path); list.append(b); print("查询完成!"); return list; if __name__ == '__main__': # 查询mysql数据库中books表中数据 books = getBooks(); num=0; for book in books: if num>10: break; print(book.name+":\t"+book.path); num+=1;
-
读取数据库内容并进一步处理,再次请求存入
from urllib.request import Request,urlopen import ssl import gzip from lxml import etree #python操作mysql所用的包 #import pymysql class Book: def __init__(self,id,name,path): self.id=id; self.name=name; self.path=path; def __str__(self): return ("id:%d name:%s path:%s"%(self,id,self.name,self.path)); class Item: def __init__(self,id,bid,name,path): self.id=id; self.bid=bid; self.name=name; self.path=path; def __str__(self): return ("第%d章:%s---%s"%(self.id,self.name,self.path)); import pymysql def saveItem(bid,name,path): #获取数据库连接对象 ''' host:连接的数据库所在的地址ip port:端口号 user:账号 password:密码 database=数据库名 charset=编码格式 ''' conn = pymysql.connect(host="127.0.0.1",port=3306,user="root", password="mysql",database="test",charset="utf8"); #获取游标,执行sql cursor = conn.cursor(); sql = "insert into items (b_id,i_name,i_path) values(%d,'%s','%s')"%(bid,name,path); #执行sql ''' 如果sql为查询语句,返回为查询结果集; 如果为增删改,返回为受影响行数 ''' result=cursor.execute(sql); if result<1: print("插入失败!"); else: #如果对数据库进行了更改就需要进行提交 conn.commit(); #关闭数据库 cursor.close() conn.close() #获取一本书的所有章节信息存入 def getData(headers,book): ssl._create_default_https_context = ssl._create_unverified_context req = Request(url=book.path,headers=headers) conn = urlopen(req) if conn.code == 200: data = conn.read() if conn.headers.get("Content-Encoding") == "gzip": data = gzip.decompress(data) itemsData = data.decode(encoding="utf-8"); itemshtml = etree.HTML(itemsData); item_aXpath = "//div[@id='list']/dl/dd/a"; item_apath= itemshtml.xpath(item_aXpath); for item_a in item_apath: i_name=item_a.xpath("./text()"); i_path = item_a.xpath("./@href"); i_path=book.path+i_path[0]; bid = book.id; # print("%s--%s"%(bookName[0],bookPath[0])); saveItem(bid,i_name[0],i_path); print("完成!"); pass else: print("错误码:",conn.code) return "" pass ''' 数据库操作 导包 pymysql ''' #python操作mysql所用的包 import pymysql def getBooks(): list=[]; # 获取数据库连接对象 conn = pymysql.connect(host="127.0.0.1", port=3306, user="root", password="mysql", database="test", charset="utf8"); # 获取游标,执行sql cursor = conn.cursor(); sql = "select * from books"; # 执行sql ''' 如果sql为查询语句,返回为查询结果集; 如果为增删改,返回为受影响行数 ''' result = cursor.execute(sql); #fetchall获得查询结果元组 result = cursor.fetchall(); for book in result: id = book[0]; name = book[1]; path = book[2]; b=Book(id=id,name=name,path=path); list.append(b); print("查询完成!"); return list; if __name__ == '__main__': headers={ "User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36", "Accept-encoding":"gzip" } # 查询mysql数据库中books表中数据 books = getBooks(); num=0; for book in books: if num>10: break; print(book.name+":\t"+book.path); #获取每本小说所有章节并存入数据库 getData(headers=headers,book=book); num+=1;
七、Flask
小技巧:创建项目,环境与代码应分开放置
1.安装flask和pymysql
pip install flask pymysql -i https://mirrors.aliyun.com/pypi/simple
2. Flask入门
-
是Python的Web的微型框架,核心实现Web服务()的WSGI规范。包含了jinja2的模板技术
-
flask只实现了核心功能,对于数据库操作需要自己实现。
-
解决8.0无法远程连接: mysql> use mysql; mysql> select user,host from user; user , host root, localhost # 不能远程连接的,必须是本地连接 mysql> update user set host='%' where user='root' and host='localhost'; mysql> grant all privileges on *.* to 'root'@'%'; mysql> flush privileges;
-
快速入门
-
- alt insert 创建文件快捷键
-
- static 静态文件夹
-
- templates 模板文件 选择template
-
flask服务的入口
"""
Flask 服务的入口脚本
"""
import json
from flask import Flask,make_response,render_template,request
#导包 DB
from db import DB
#导包
from spider_book import get_book
#ctrl+p(ctr+鼠标)显示方法参数
app = Flask(__name__,static_url_path="/s",static_folder="static")
#声明站点的主页资源(动态资源)
@app.route('/' , methods=['Get'])#装饰器---java的注解
def index_handle():
# 当实例对象使用with 进入上下文时,会调用对象的__enter__方法
# 当实例退出上下文时,会调用对象的__exit__方法
with DB() as c:
c.execute('select * from books')
ret = list(c.fetchall())
return render_template('index.html',
title="我是书库",
books=ret)
@app.route('/search',methods=['GET','POST'])
def search_handle():
# GET 请求 获取资源
# POST 请求 上传资源
# flask.request 对象存储了客户端请求过来的相关数据(请求报文中提取)
kw = request.form.get('kw','');#是字典格式
ret=None;
if request.method == 'POST':
# 处理搜索功能
# 读取表单数据中的kw字段值
sql ="""
select * from books
where b_name like %s
"""
with DB() as c:
# If args is a list or tuple, %s can be used as a placeholder in the query.
# If args is a dict, %(name)s can be used as a placeholder in the query.
c.execute(sql,args=(f'%{kw}%',))
ret = list(c.fetchall())
return render_template('search.html',kw=kw,results=ret)
@app.route('/spider',methods=['GET'])
def spider_handle():
# 获取请求参数path
path = request.args.get("path")
# 根据path获取book
book=get_book(path)
#json.dumps() 将dict或list对象转为json格式的字符串
# json格式: 对象{"key":"value"...},数组:[{},{}]
# resp_data = json.dumps({'code':100,'msg':'OK'})
resp_data = json.dumps(book)
response = make_response(resp_data)
response.headers['Content-Type'] = 'application/json;charset=utf-8'
return response #返回json数据
#渲染
# return render_template("book.html",book=book)
if __name__ == '__main__':
app.run(host="0.0.0.0",port=5000,debug=True)
- 数据库的工具类
from pymysql import Connect
from pymysql.cursors import DictCursor
# 进入到mysql客户端
"""
mysql> use mysql;
mysql> select user,host from user;
user , host
root, localhost # 不能远程连接的,必须是本地连接
mysql> update user set host='%' where user='root' and host='localhost';
mysql> grant all privileges on *.* to 'root'@'%';
mysql> flush privileges;
"""
DB_CONFIG = {
#180.76.121.47
'host':'127.0.0.1',
#3307
'port':3306,
'user':'root',
#root
'password':'mysql',
'db':'test',
'charset':'utf8'
}
class DB:
def __init__(self):
# **xx 把xx转换成对应的关键字
self.conn =Connect(**DB_CONFIG,
cursorclass=DictCursor)
print('--数据库连接成功!--')
def __enter__(self):
#进入上下文的方法,当前实例在with中使用
return self.conn.cursor() #返回游标实例
def __exit__(self, exc_type, exc_val, exc_tb):
#退出上下文方法,当前实例在退出with上下文时
if exc_type:
#执行sql出现的异常
#回滚事务
self.conn.rollback()
print('--->db_error:',exc_val)
else:
#sql执行成功的
#提交事务
self.conn.commit()
return True #True 异常已内部消化. False:异常继续抛出
def create_db(self,name):
with self as c:
c.execute(f'create database {name} charset utf8')
def create_table(self,table_name,*fields):
# fields ->('id integer','name varchar(20) ')
with self as c:
sql = 'create table %s (%s)'
field_args=','.join(fields)
c.execute(sql%(table_name,field_args))
if __name__ == '__main__':
# 当实例对象使用with 进入上下文时,会调用对象的__enter__方法
# 当实例退出上下文时,会调用对象的__exit__方法
with DB() as c:
# c.execute("show tables")
c.execute('desc books')
for row in c.fetchall():
print(row)
#创建数据库或者表
db=DB()
# db.create_db('group1');
# db.create_table('',('','',''))
书城网站首页
动态获取的浏览器驱动下载
有任何问题,欢迎私信我~