【实训总结】Python从入门到前端知识小结,再到Flask框架搭建在线书城~

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项目,需要前端展示,也需要会前端网页

代码学习路径
  1. 搭建环境

  2. 安装开发工具

  3. 创建项目

    ​ 项目结构
    ​ css:存放css代码文件
    ​ img:存放项目中使用的图片文件,注意网页支持gif图
    ​ js:存放js代码文件
    ​ index.html:项目自带的网页文件
    ​ 注意:一个项目中,可以有多个网页文件

  4. 编写代码

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.静态爬取
  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("连接失败");
  1. 爬取目录,然后进入具体列表项爬
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.资源下载(图片、文件、视频)
  1. 图片获取
'''
网络请求的包
    请求: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.动态资源获取
  1. 动态百度图爬取

    #谷歌浏览器包
    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. 爬取数据存入数据库
  1. 存入数据库

    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);
    
    
  2. 读取数据库

    #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;
    
  3. 读取数据库内容并进一步处理,再次请求存入

    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('',('','',''))

书城网站首页
在这里插入图片描述
动态获取的浏览器驱动下载

有任何问题,欢迎私信我~
  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Itfuture03

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值