文章目录
pycharm环境搭建
[Python 项目管理的利器:虚拟环境 venv 的使用_(ÒωÓױ)-优快云博客_python虚拟环境venv](https://blog.youkuaiyun.com/u012814856/article/details/81137368#:~:text=Python 自带的 venv 可以创建一个独立的 虚拟环境 ,在命令行中 使用python -m,-m venv Fuck 执行后便会在F盘下创建一个名叫Fuck的文件夹,这是一个可以 使用 的 python 环境。)
详细了解PyCharm支持的4种Python Interpreter和配置方法
什么是虚拟环境、为什么使用虚拟环境、Anaconda创建、激活、退出、删除虚拟环境
0.anaconda虚拟环境的创建
conda create -n xxx(你要设置的环境名称) python=3.6
1.激活环境
activate env_name(环境名称)
2.停用环境
deactivate | conda deactivate | activate root
3.删除环境
conda remove -n [your_env_name(虚拟环境名称)] --all, 即可删除。
4.删除虚拟环境中的包
conda remove --name [your_env_name] [package_name](包名) 即可。
conda env list 或 conda info -e:查看当前存在哪些虚拟环境
虚拟环境重命名(clone old to new and then delete old venv)
1.拷贝一份
conda create -n [new venvname] --clone [old venvName]
2.删除旧的
conda remove -n [old venvName] --all
3.检查结果
conda info -e
pip config set global.index-url https://pypi.tuna.tsinghua.edu.cn/simple
#备选
清华:https://pypi.tuna.tsinghua.edu.cn/simple
阿里云:http://mirrors.aliyun.com/pypi/simple/
中国科技大学 https://pypi.mirrors.ustc.edu.cn/simple/
华中理工大学:http://pypi.hustunique.com/
山东理工大学:http://pypi.sdutlinux.org/
豆瓣:http://pypi.douban.com/simple/
python软件相关杂项
当用python用得多了的时候,系统里很容易存在多个python解释器,这时候自己很容易被搞糊涂。我的建议是:在系统的环境变量中只配置自己最常用的那一个解释器所在的目录,并将其作为一个全局解释器,在其他地方需要单独的python解释器的时候,使用虚拟环境(可以用vitutual或pypenv等工具手动创建,也可以用pycharn这类集成开发环境在创建项目时自动创建,不过不管是在哪里创建,都一定得注意要基于一个可靠的python解释器创建!)
当语句以冒号:
结尾时,缩进的语句视为代码块
Python程序是大小写敏感的,如果写错了大小写,程序会报错
python基础
数据类型:
python这种变量本身类型不固定的语言称之为动态语言,与之对应的是静态语言。静态语言在定义变量时必须指定变量类型,如果赋值的时候类型不匹配,就会报错
整数:
Python允许在数字中间以_
分隔,因此,写成10_000_000_000
和10000000000
是完全一样的。十六进制数也可以写成0xa1b2_c3d4
浮点数:
1.23x109就是1.23e9
,或者12.3e8
,0.000012可以写成1.2e-5
字符串:
- Python中的字符串不能改变。
- 字符串可以用+运算符连接在一起,用*运算符重复。
字符串是以单引号'
或双引号"
括起来的任意文本,比如'abc'
,"xyz"
等等。请注意,''
或""
本身只是一种表示方式,不是字符串的一部分,因此,字符串'abc'
只有a
,b
,c
这3个字符。如果'
本身也是一个字符,那就可以用""
括起来,比如"I'm OK"
包含的字符是I
,'
,m
,空格,O
,K
这6个字符
如果字符串内部既包含'
又包含"
可以用转义字符\
来标识,比如:
'I\'m \"OK\"!'
表示的字符串内容是:
I'm "OK"!
转义字符\
可以转义很多字符,比如\n
表示换行,\t
表示制表符,字符\
本身也要转义,所以\\
表示的字符就是\
Python还允许用r''
表示''
内部的字符串默认不转义
>>> print("\\\t\\")
\ \
>>> print(r"\\\t\\")
\\\t\\
>>> print(r"\n")
\n
用\n
写在一行里不好阅读,为了简化,Python允许用'''...'''
的格式表示多行内容
注意在输入多行内容时,提示符由>>>
变为...
,提示你可以接着上一行输入,注意...
是提示符
>>>print('''I
...love
.you''')
布尔值:
True, False, and, or, not
bool(0)
空值
空值是Python里一个特殊的值,用None
表示。None
不能理解为0
,因为0
是有意义的,而None
是一个特殊的空值。
变量
变量不仅可以是数字,还可以是任意数据类型。
变量在程序中就是用一个变量名表示了,变量名必须是大小写英文、数字和_
的组合,且不能用数字开头
常量
所谓常量就是不能变的变量,比如常用的数学常数π就是一个常量。在Python中,通常用全部大写的变量名表示常量
但事实上PI
仍然是一个变量,Python根本没有任何机制保证PI
不会被改变,所以,用全部大写的变量名表示常量只是一个习惯上的用法
/
除法计算结果是浮点数,即使是两个整数恰好整除,结果也是浮点数
//
,称为地板除,两个整数的除法仍然是整数
字典
- 不允许同一个键出现两次。后来者覆盖
- 字典值可以是任何的 python 对象,既可以是标准的对象,也可以是用户定义的,但键不行。
- 键必须不可变,所以可以用数字,字符串或元组充当,而用列表就不行
len(dict) #计算字典元素个数,即键的总数
str(dict) #输出字典,以可打印的字符串表示。
>>> dict = {'Name': 'Runoob', 'Age': 7, 'Class': 'First'}
>>> str(dict)
"{'Name': 'Runoob', 'Class': 'First', 'Age': 7}"
type(variable) #返回输入的变量类型,如果变量是字典就返回字典类型。
切片(Slice)
- 取序列中指定范围内的元素
- 支持倒数第几个地取数L[-1]表示倒数第一个
#表示[0, 3)
L[0:3]
L[:3]
#取前十个
L[:10]
#取后十个
L[-10:]
#取倒数后两个
L[-2: -1]
L[-2:]
#前10个数,每两个取一个 L[i:j:k] :slice of s from i to j with step k
L[:10:2]
#[0, 2, 4, 6, 8]
#什么都不写可以复制一个list
L[:]
python多变量赋值
分两步执行的:1. 先从左往右计算等号右边的表达式 2.将变量从左往右依次赋值
函数
print(r"") #字符串中不转义
name = input('输入名字')
print(f"he name is {name}") #字符串中显示name
strip() # 去除字符串首尾的空格或者字符
lstrip() # 去除字符串左侧的空格或者字符
replace(old, new [, max]) # 替换字符串中的old为new,若指定max,则替换不超过max次
split(s, num) # str以s为分隔符,分割成 num+1 份,s默认为所有空字符,num默认为-1全部分割
>>>"{0} name is {1}, not jk".format("he", "jack")
'he name is jack, not jk'
对齐,填充
print('welcome'.center(20, '*')) # 居中,宽度20,填充*
print(bin(5).replace('0b', '').rjust(5, '0')) # 右对齐,宽度5,填充0
print('welcome'.ljust(20)) # 左对齐,宽度20,默认填充空格
print(format(bin(6).replace('0b', ''), '0<5')) # ’0<5': 0:填充符,<:左对齐,5:宽度 # >:右填充,^:居中
print(i, end=' ')
# 输出 0~19 二进制右对齐形式
for it in range(20):
# print(bin(it).replace('0b', '').rjust(5, '0'))
print(format(bin(it).replace('0b', ''), '0>5'))
lru缓存优化
Python 中 lru_cache 的使用和实现 - zikcheng - 博客园 (cnblogs.com)
import
模块
搜索路径是由一系列目录名组成的,Python解释器就依次从这些目录中去寻找所引入的模块
import xxx
这样做并没有把直接定义在 xxx 模块中的函数名称写入到当前符号表里,只是把模块 xxx 的名字写到了那里
可以使用模块名称来访问函数 xxx.func()
(模块是可以导入其他模块的,被导入的模块的名称将被放入当前操作的模块的符号表中,每个模块有各自独立的符号表,在模块内部为所有的函数当作全局符号表来使用)
如经常使用一个函数,你可以把它赋给一个本地的名称 func = xxx.func()
from xxx import funcName
from xxx import name1[, name2[, ... nameN]]
你从模块中导入一个指定的部分到当前命名空间中,这种导入的方法不会把被导入的模块的名称放在当前的字符表中(所以在这个例子里面,xxx 这个名称是没有定义的)
>>>from xxx import func1,func2
>>>fun1(a)
from ... import *
把一个模块的所有内容全都导入到当前的命名空间
使用from ... import ...
导入变量时,只相当于导入一个变量的副本,并不会影响在原文件中的变量
__name__
属性
一个模块被另一个程序第一次引入时,其主程序将运行。如果我们想在模块被引入时,模块中的某一程序块不执行,我们可以用__name__
属性来使该程序块仅在该模块自身运行时执行
每个模块都有一个 __name__
属性,当其值是 __main__
时,表明该模块自身在运行,否则是被引入
内置函数dir()
内置的函数 dir()
可以找到模块内定义的所有名称,如dir(sys)
>>>del virableName
可以删除变量名
sys 模块
sys 模块内置在 Python 解析器中
变量 sys.ps1 和 sys.ps2 定义了主提示符和副提示符所对应的字符串
>>> import sys
>>> sys.ps1
'>>> '
>>> sys.ps2
'... '
>>> sys.ps1 = 'C> '
C> print('Runoob!')
Runoob!
C>
sys.path 中的存储了搜索路径(用于查找模块时,模块可能存在于哪些目录中)
变量作用域
python全局变量(模块法和global)_谢一鸣_123的博客-优快云博客
包
6. Modules — Python 3.9.7 documentation
The
__init__.py
files are required to make Python treat directories containing the file as packages. This prevents directories with a common name
__init__.py
:一个空文件,告诉 Python 这个目录应该被认为是一个 Python 包
from package import item
可以导入子包、函数、类、变量等
包是一种管理 Python 模块命名空间的形式,采用"点模块名称"
一个模块名称是 A.B,表示包 A 中的子模块 B
classmethod
python @classmethod - 筱筱的春天 - 博客园 (cnblogs.com)
一个类中,某个函数前面加上了staticmethod或者classmethod的话,那么这个函数就可以不通过实例化直接调用,
可以通过类名进行调用的
由于Python不支持多个的參数重载构造函数,python採用classmethod修饰符的方式,这样定义出来的函数就能够在类对象实例化之前调用这些函数,就相当于多个构造函数,解决多个构造函数的代码写在类外面的问题。
正则表达式(regular expression)
ABC
正则表达式 – 教程 | 菜鸟教程 (runoob.com)
练习
RegExr: Learn, Build, & Test RegEx
RegexOne - Learn Regular Expressions - Lesson 1: An Introduction, and the ABCs
速查
阿里大佬整理的常用正则表达式大全-技术圈 (proginn.com)
Regular Expression Language - Quick Reference | Microsoft Docs
https://jex.im/regulex 可视化
已学
标记、普通字符、特殊字符、非打印字符、限定符、定位符、选择、后向引用、贪婪、断言(正向预查、反向预查)
待学
递归、平衡组 等
历史
Warren McCulloch 和 Walter Pitts 这两位神经生理学家研究出一种数学方式来描述人类神经网络。
1956 年, 一位叫 Stephen Kleene 的数学家在 McCulloch 和 Pitts 早期工作的基础上,发表了一篇标题为"神经网事件的表示法"的论文,引入了正则表达式的概念。正则表达式就是用来描述他称为"正则集的代数"的表达式,因此采用"正则表达式"这个术语。
Unix 的主要发明人之一 Ken Thompson 发现可以将这一工作应用于计算搜索算法的一些早期研究。正则表达式的第一个实用应用程序就是 Unix 中的 qed 编辑器。
作用
-
测试字符串内的模式
- 数据验证:可以测试输入字符串,以查看字符串内是否出现电话号码模式或信用卡号码模式。
-
替换文本 :识别文档中的特定文本,完全删除该文本或者用其他文本替换它。
-
基于模式匹配从字符串中提取子字符串
正则表达式 – 语法 | 菜鸟教程 (runoob.com)
正则表达式的组件可以是单个的字符、字符集合、字符范围、字符间的选择或者所有这些组件的任意组合。
模式描述在搜索文本时要匹配的一个或多个字符串。正则表达式作为一个模板,将某个字符模式与所搜索的字符串进行匹配。
正则表达式是由普通字符(例如字符 a 到 z)以及特殊字符(称为"元字符")组成的文字模式。
若要匹配这些特殊字符,必须首先使字符"转义",即,将反斜杠字符**\** 放在它们前面
正则表达式
/pattern/flags
flags为标记,也称修饰符
i ignore - 不区分大小写
g global - 全局匹配
m multi line - 多行匹配,使边界字符 ^ 和 $ 匹配每一行的开头和结尾,记住是多行,而不是整个字符串的开头和结尾。
s 特殊字符圆点 . 中包含换行符 \n,一般 . 表示匹配除换行符 \n
之外的任何字符,加上 s 之后就会包含 \n
字符
[] 表示字符集合
非打印字符
特殊字符(元字符)
具有固定含义的特殊符号
- 如果要查找字符串中的 ***** 符号,则需要对 ***** 进行转义,即在其前加一个 \,runo*ob 匹配字符串 runo*ob。
- ? 代表前面的字符最多只可以出现 0 , 1 次
- ***** 代表前面的字符可以出现 0 ,1 , ∞ \infty ∞ 次
- . 匹配除换行符 \n 之外的任何单字符。
- + 代表前面的字符必须至少出现一次
- () 分组,捕获,标记一个子表达式的开始和结束位置。
- | 运算符,与分组搭配使用,
/a (dog|cat) aha/g
匹配 a dog aha或着 a cat aha,/a dog|cat aha/g
匹配 a dog 或者 cat aha - ^ 为匹配输入字符串的开始位置。当该符号在方括号表达式中使用时,表示不包含方括号中的字符集合
- **
∗
∗
为
匹
配
输
入
字
符
串
的
结
束
位
置
,
∗
∗
a
b
c
** 为匹配输入字符串的结束位置,**abc
∗∗为匹配输入字符串的结束位置,∗∗abc**匹配以 abc 结尾的,
^xxx$
的使用可以保证匹配的安全性 - […] 方括号内是字符集,匹配字符集中的所有字符
- [0-9]+匹配多个数字, [0-9] 匹配单个数字,+ 匹配一个或者多个。
- \ 将下一个字符标记为或特殊字符、或原义字符、或向后引用、或八进制转义符。
- \w 匹配单词字符(字母、数字、下划线)。等价于 [A-Za-z0-9_]
- \s 是匹配所有空白符,包括换行,\S 非空白符,不包括换行。
- \S、\D、\W 均表示小写的时 \s、\d、\w 的反义,非空格字符、非数字字符、非单词字符。
[正则表达式\W+、(\W+)、(\W)+、\W]+、[\W+]分割时候的区别_weixin_44356698的博客-优快云博客
限定符(量词)
控制前面的元字符出现的次数
有 ***** 或 + 或 ? 或 {n} 或 {n,} 或 {n,m} 共6种。
限定符用来指定正则表达式的一个给定组件必须要出现多少次才能满足匹配。
{n,m} m, n >= 0 && n <= m , 最少匹配 n 次且最多匹配 m 次。
a* 等价于 a{0,}
a+ 等价于 a{1,}
a? 等价于 a{0,1}
请注意在逗号和两个数之间不能有空格。
定位符(锚位符anchor)
-
^ 匹配输入字符串开始的位置 ,若在圆括号 () 中,就是排除的意思
-
** ∗ ∗ 匹 配 输 入 字 符 串 结 尾 的 位 置 , ∗ ∗ a b c ** 匹配输入字符串结尾的位置,**abc ∗∗匹配输入字符串结尾的位置,∗∗abc**匹配以 abc 结尾的
-
\b 匹配一个单词边界,即字与空格间的位置。
对于
abcabc abce eabc
/abc\b/g
匹配结果 abcabc abce eabc
/\babc/g
匹配结果 abcabc abce eabc
- \B 非单词边界匹配,在字符串中间匹配,即只在字符串“abcde” 中的 “bcde” 里搜索
/\Babc/g
匹配结果 abcabc abce eabc
/abc\B/g
匹配结果 abcabc abce eabc
正则表达式单词边界和非单词边界 - 海之殇 - 博客园 (cnblogs.com)
贪婪匹配与惰性匹配
***** 和 + 限定符都是贪婪的,因为它们会尽可能多的匹配文字,只有在它们的后面加上一个 ? 就可以实现非贪婪(懒惰)或最小匹配。
贪婪: /<.+>/g
懒惰: /<.+?>/
/<.*>/g
<h1>RUNOOB-菜鸟教程<h1>
会匹配到全部
/<.*?>/g
<h1>RUNOOB-菜鸟教程<h1>
会匹配到<h1>
选择
用圆括号 () 将所有选择项括起来,表示要提取的分组,也称捕获,相邻的选择项之间用 | 分隔。
后向引用:正则表达式模式或部分模式两边添加圆括号**()** 会将匹配到的子串临时缓冲起来,通过\number 来访问
/(x)\1/g
该正则是想匹配到第一个字符是x,第二个字符也是x,即两个相同的x,即匹配xx
/(a)(x)\1/g
该正则是想匹配到第一个字符是a,第二个字符是x,第三个字符是a,即匹配axa,
/(x)(y)\2/g
该正则是想匹配到第一个字符是x,第二个字符是y,第三个字符也是y的内容,即匹配xyy,但是xya、xyb就不能被匹配到。
/(.)\1/g
该正则是想匹配任意对子字符,如aa,bb,xx,yy这样
另外如果 \1 前没有捕获的分组的表达式(即用括号括起来的匹配)时,则 \1 表示匹配八进制数字1
正则表达式中有两类断言:Anchors(定位符相关)和Lookarounds(正向预查相关)。
正则表达式中的断言(assertions) - 简书 (jianshu.com)
而很多时候,我们添加一个子模式,并不是为了在后向引用中获取它,我们或许是出于匹配需要,或许简单的只是为了使表达式更清晰。可以使用非捕获元字符 ?:、?= 或 ?! 来重写捕获,忽略对相关匹配的保存。
非获取(捕获)匹配:就是只进行匹配,并不保存结果供以后引用。可以提高性能和简化逻辑。
(?:re) 放在第一个选项前可以去除相关的匹配被缓存
(?=re) 为正向预查(lookahead),在任何开始匹配圆括号内的正则表达式模式的位置来匹配搜索字符串
expa(?=expb)
查找 expb 前面的 expa
(?<=re)
(?<=expb)expa
查找 expb 后面的 expa
(?!re) 为负向预查,在任何开始不匹配该正则表达式模式的位置来匹配搜索字符串。
expa(?!expb)
查找后面不是 expb 的 expa
(?<!re)
(?<!expb)expa
查找前面不是 expb 的 expa
(?P<name>) 分组起别名,比如 (?P<value>\d)
匹配后的结果调 m.group(’value‘)
可以拿到 value组 匹配到的结果
python 中的正则表达式
python 正则表达式re使用模块(match()、search()和compile()) - 风雨一肩挑 - 博客园 (cnblogs.com)
Python3 正则表达式 | 菜鸟教程 (runoob.com)
无捕获组和命名组 | Python 正则表达式操作指南 (jb51.net)
返回的结果是 Match 或则 迭代器,可以用 .group()
来获取数据
import re
re.match() #相当于/^expression/g 从头开始匹配 re.match(pattern, string, flags=0)
re.search() #类似于/expression/g 匹配到一项就返回Match对象 re.search(pattern, string, flags=0)
re.findall() #相当于/expression/g re.findall(pattern, string, flags=0) pattern.findall(string[, pos[, endpos]])
# e.g.:
# lst = re.findall(r"\d+", "我的电话号码是:19898, 我老师的电话号码是:13141")
# print(lst)
#
# ['19898', '13141']
re.finditer() #和findall功能相同,但返回的是迭代器,从迭代器中拿到内容需要.group()
# it = re.finditer(r"\d+", "我的电话号码是:19898, 我老师的电话号码是:13141")
# for i in it:
# print(i.group())
#
# 19898
# 13141
group(num) #返回第num个捕获到的组,res.group('name')或 res[返回组名对应的内容
groups() #返回所有捕获到的组
span() #返回匹配到的分组的下标范围[start, end)
re.sub() #用于替换字符串中的匹配项 re.sub(pattern, repl, string, count=0, flags=0)
#repl:替换的字符串,也可为一个函数。模式匹配后替换的最大次数,默认 0 表示替换所有的匹配。
re.compile() #编译(预加载)正则表达式,生成一个正则表达式(pattern)对象,供 match() 和 search()使用 re.compile(pattern[, flags])
# e.g.
# pattern = re.compile(r'\d+')
# m = pattern.match('one12twotree34') 从头部开始匹配
#e.g.
# pattern = re.compile(r'\d+')
# m = pattern.match('one12twotree34', 3, 10) 从'1'的位置开始匹配,正好匹配返回一个match对象
pattern.findall()#pattern.findall(string[, pos[, endpos]]) string后面的[]表示可省略的意思
pattern.match() #pattern.match(string, pos=0, endpos=len(string)) 匹配成功后返回一个 Match 对象
# (?P<分组名字>正则) 可以单独从正则匹配的内容中进一步提取内容
小点心🍙
-
阅读官方文档时,
pattern.findall(string[, pos[, endpos]])
文档默认约定方括号[]中的参数是可省略的, 即可以写成pattern.findall(str, 0)
(表0下标处开始用pattern匹配str到末尾) 或者pattern.findall(str, 5, len(str))
(表从5下标处开始用pattern匹配str到末尾) -
正则表达式前加
r
表示 string 是 raw string(原字符串),不要转义反斜杠,比如string = ‘I love \n’,其中的\n 表示 ‘\’ 和 ‘n’ 两个字符连接无其他意思。
由于正则表达式通常都包含反斜杠,所以你最好使用原始字符串来表示它们。模式元素(如 r’\t’,等价于 \t )匹配相应的特殊字符。
- 请通过以下方式检查您的工作目录:
import os
print(os.path.abspath('.'))
python 爬虫
参考
https://www.bilibili.com/video/BV1i54y1h75W
http协议
请求
请求行
方式(get/post)、地址、协议
请求头
供服务器使用的附加信息(where)
参数
referer(参照页):表示你是从哪个网页来到这个网页的
Headers之Referer设置 - 知乎 (zhihu.com)
host()
请求体
请求参数(搜索:xxx)
响应
响应行 状态码、协议
响应头 放在客户端要使用的附加信息(cookie、密钥等),与请求头对应
响应体 内容 html、json
服务器渲染 一步到位
客户端渲染 二次:先获取html骨架,后获取数据
pycharm
terminal 里输入
pip install request
数据获取
如果是服务器渲染,则直接匹配页面 html 源代码中的数据
如果是客户端渲染,一般会有专门获取json格式数据的链接,应该去匹配该链接响应的结果
编码 、乱码
- 乱码的产生: 显示的编码与本身不一致
- 查看页面源码的编码方式 Ctrl + F : charset
页面编码:gbk
显示编码:utf-8
python中两种字符串:str、unicode
gbk -> unicode -> uft-8
decode(解码):把一种编码换成 unicode
encode(解码):把 unicode 转换成一种编码
代码示例
from urllib.request import urlopen
resp = urlopen("https://www.xxx.com/data/flights/am915")
print(resp.read().decode("utf-8"))
import requests
# 修改请求头反爬,F12 中的network 里查看
headers = {
'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36 Edg/92.0.902.55'
}
url = 'https://www.xxx.com/data/flights/am915'
resp = requests.get(url, headers=headers)
# 显示状态
print(resp)
# 显示请求的头部
print(resp.request.headers)
# 显示响应的文本
print(resp.text)
resp.close() # 别忘了关掉 resp
import requests
url = "https://fanyi.baidu.com/sug"
s = input("请输入要翻译的英文单词:")
dict = {
'kw' : s
}
# 发送 post 请求,发送的数据必须放在字典中,通过 data 参数进行传递
resp = requests.post(url, data=dict)
print(resp.json()) # 将服务器返回的内容直接处理还曾jason() => dict
resp.close() # 别忘了关掉 resp
import requests
url = 'https://movie.douban.com/j/chart/top_list'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36 Edg/92.0.902.55',
'connection': 'close' # 默认是keep-alive,设置成 close 表示只取一次数据,就不用手动 resp.close()
}
# 重新封装参数
param = {
'type': '6',
'interval_id': '100:90',
'action': '',
'start': '40',
'limit': '20',
}
resp = requests.get(url, params=param, headers=headers)
print(resp.request.url)
print(resp.text) #输出不美观就换成json()
print(resp.json())
print(resp.request.headers) # 打印无反应,则需查看并手动修改headers
import re
import requests
import csv
def get_douban_rank(idx):
# 获取页面数据
url = "https://movie.douban.com/j/chart/top_list"
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) '
'AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36 Edg/92.0.902.55'
}
params = {
'type': '5',
'interval_id': '100:90',
'action': '',
'start': str(idx),
'limit': '20',
}
resp = requests.get(url, headers=headers, params=params)
resp.close()
page_content = resp.text
# 解析数据数据,生成预加载正则表达式,进行匹配,
pattern = re.compile(r'"title":"(?P<title>.*?)".*?"score":"(?P<score>.*?)"')
result = pattern.finditer(page_content)
with open('data.csv', mode='a', encoding='utf-8', newline='') as f:
csvwriter = csv.writer(f)
for it in result:
# print(it.group('title'), end=" ")
# print(it.group('score'))
dic = it.groupdict() #将匹配到的数据以字典形式返回
csvwriter.writerow(dic.values())
print("over!")
if __name__ == '__main__':
for i in range(0, 100, 20):
get_douban_rank(i)
import time
import re
import requests
import csv
def get_page_info(idx):
# 获取页面数据
url = "https://www.xxx.com/data/registration/" + idx
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) '
'AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/92.0.4515.107 Safari/537.36 Edg/92.0.902.55',
'referer': 'https://www.xxx.com/data/registration'
}
# referer 表示从哪个网页跳转到当前页,用于应对反爬虫
resp = requests.get(url, headers=headers)
resp.close()
# print(resp)
page_content = resp.text
# 解析数据数据,生成预加载正则表达式,进行匹配,
pattern = re.compile(r'Aircraft Info</div><.*?>Aircraft Model</div><.*?><.*?>(?P<aircraftmodel>.*?)</a><.*?>'
r'Registration</div><.*?><.*?>(?P<registeration>.*?)<.*?>'
r'Mode-S</div><.*?><.*?>(?P<modes>.*?)</a>.*?'
r'Serial Number</div><div id="value">(?P<serial_number>.*?)</div>.*?'
r'Last activity</div><div id="value">(?P<last_activity>.*?)</div>.*?'
r'Last Known Location</div><div id="value">(?P<last_know_location>.*?)</div>')
result = pattern.finditer(page_content)
with open('data.csv', mode='a', encoding='utf-8', newline='') as f:
csv_writer = csv.writer(f)
for it in result:
dic = it.groupdict()
# dic['serial_number'] = str(dic['serial_number'])
csv_writer.writerow(dic.values())
def get_page_idx(page_num):
url = 'https://www.xxx.com/search/active/registrations'
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) '
'AppleWebKit/537.36 (KHTML, like Gecko) '
'Chrome/92.0.4515.107 Safari/537.36 Edg/92.0.902.55'
}
# parems 中有一项属性 maxdeps 是实时增长的,所以缺省处理
params = {
'page': str(page_num),
'q': '',
}
resp = requests.get(url, headers=headers, params=params)
resp.close()
page_content = resp.text
pattern = re.compile(r'"cs":"(?P<cs>.*?)".*?"fnia":(?P<fnia>.*?),.*?')
# 分析发现 params不是 fnia 就是 cs,若 fnia 为 null,那么 params 就是 cs,
# cs 始终有值”xxx“,fnia 要么是 ”xxx“ 要么是 null
idx_list = pattern.finditer(page_content)
i = 0
for it in idx_list:
if it.group("fnia") == 'null':
idx = it.group("cs")
else:
idx = it.group("fnia").strip("\"")
# print(f"{i} ", i, end=" ")
get_page_info(idx)
i += 1
print("get", i)
time.sleep(0.5)
def init_cvs():
spider_time = "spider_time = " + time.ctime()
list_name = ["AIRCRAFT MODEL", 'REGISTRATION', 'MODE-S', 'SERIAL NUMBER', 'LAST ACTIVITY', 'LAST KNOWN LOCATION',
spider_time]
with open('data.csv', mode='w', encoding='utf-8', newline='') as f:
csv_writer = csv.writer(f)
csv_writer.writerow(list_name)
def main():
init_cvs()
j = 0
page_num = int(input("请输入要抓取多少组数据30个为一组:")) + 1
for page_num in range(1, page_num):
get_page_idx(page_num)
j += 1
print(f"Get page{j}'s data!")
print('Finished!')
if __name__ == '__main__':
main()
'''
编码逻辑:
要爬取多个航班的信息,先写爬取单个页面航班信息的代码,再对多个航班页面做同样的操作
而访问某一个航班的页面,我们需要有该页面的链接,一般同类型的页面,其访问链接前缀是固定的,往往是 www.xxx.com/xxx/xxx?params ,
这个params就是我们访问同类型某个页面需要的参数,该参数是由导航页面得到的,所以我们先要对导航导航页面做一个数据获取和提取的操作(获取+提取=爬虫),
这样一来我们就有了访问单个页面所需的params,然后对于单个页面再来做爬虫的操作,获取我们需要的数据
在每个环节我们还需做些小测试,比如
1.发送的request请求能正常响应,如果不能通常需修改请求头 headers 中的 user-agent 参数来应对反爬虫
2.我们爬取出用去写params的导航页面的数据后,需测试该params是否有效(请求到单个网页后输出访问状态print(resp),
3.检测正则表达式能否准确捕获想要的数据
注意:
由于所要爬取的航班页面是不断更新的,所以每次爬取数据,都会重置 csv 表,即打开方式是 ‘w',而多个页面的的查询则是追加方式 'a'
Mods-s 表示雷达站台 https://shop.jetvision.de/Blog/What-actually-is-Mode-A/C-Mode-S-and-ADS-B
'''
scrapy框架
Scrapy框架流程图解析_田田&味道的博客-优快云博客_scrapy框架
Scrapy1.5中文文档_Scrapy1.5中文文档_Scrapy 中文网 (scrapyd.cn)
python连接到常用数据库(SQLite,Mysql,Mongodb,redis) - 知乎 (zhihu.com)
scrapy 保存到 sqlite3 - 罗兵 - 博客园 (cnblogs.com)
浅析Scrapy框架运行的基本流程 - 心灵蚂蚁 - 博客园 (cnblogs.com)
Scrapy 2.5 documentation — Scrapy 2.5.0 documentation
初窥Scrapy — Scrapy 0.24.1 文档 (scrapy-chs.readthedocs.io)
settings设置,为了使三种pipeline均生效需要设置如下 数字越小优先级越高
insert_sql = "insert into {0}({1}) values ({2})".format(self.sqlite_table,
', '.join(item.fields.keys()),
', '.join(['?'] * len(item.fields.keys())))
Django
参考
Django 文档 | Django 文档 | Django (djangoproject.com)
快速开始
MVT model view template
py -m django --version
查看是否安装好Django
django-admin start project mysite
创建项目
- 最外层的
mysite/
根目录只是你项目的容器, Django 不关心它的名字,你可以将它重命名为任何你喜欢的名字。 manage.py
: 一个让你用各种方式管理 Django 项目的命令行工具。你可以阅读 django-admin and manage.py 获取所有manage.py
的细节。- 里面一层的
mysite/
目录包含你的项目,它是一个纯 Python 包。它的名字就是当你引用它内部任何东西时需要用到的 Python 包名。 (比如mysite.urls
). mysite/__init__.py
:一个空文件,告诉 Python 这个目录应该被认为是一个 Python 包。如果你是 Python 初学者,阅读官方文档中的 更多关于包的知识。mysite/settings.py
:Django 项目的配置文件。如果你想知道这个文件是如何工作的,请查看 Django 配置 了解细节。mysite/urls.py
:Django 项目的 URL 声明,就像你网站的“目录”。阅读 URL调度器 文档来获取更多关于 URL 的内容。mysite/wsgi.py
:作为你的项目的运行在 WSGI 兼容的Web服务器上的入口。阅读 如何使用 WSGI 进行部署 了解更多细节。
py manage.py runserver
启动项目 (默认127.0.0.1 8000端口上)
默认情况下,runserver
命令会将服务器设置为监听本机内部 IP 的 8000 端口。
py manage.py runserver 8080
更改监听端口
py manage.py runserver 0:8000
更改监听ip (0是0.0.0.0的缩写)
wsgi
python 组织制定了 web 服务网关接口(Web Server Gateway Interface) 规范 ,简称wsgi
https://www.python.org/dev/peps/pep-3333/
将后端分离成 server 和 application
-
server 负责高效接受 http 请求,并将业务逻辑交给 application 处理。wsgi web server 可以多线程、多进程、多协程实现。
-
application 负责处理 http 请求的业务逻辑
Django 核心是做 application 板块,他只有一个简单的单线程 wsgi web server,server 板块有 gunicorn, uwsgi, cherrypy 等框架高效实现
Django app模块
Django 中的app,就是一个独立的处理业务逻辑的功能模块
一个项目中包含多个 app,本质就是 Python 包
ORM(object relational mapping)
在Django中
- 定义一张数据库的表 就是定义一个继承自 django.db.models.Model 的类
- 定义该表中的字段(列), 就是定义该类里面的一些属性
- 类的方法就是对该表中数据的处理方法,包括 数据的增删改查
这样,开发者对数据库的访问,从原来的使用底层的 sql 语句,变成 面向对象的开发,通过一系列对象的类定义 和方法调用就可以 操作数据库。通过 对象 操作数据库 的方法 被称之为 ORM。
优点
- 极大的简化了我们应用中的数据库开发,因为无需使用sql语句操作数据库了, 提高了开发的效率;
- 屏蔽了 不同的数据库访问的底层细节,基本做到了 开发好代码后,如果要换数据库,几乎不需要改代码, 修改几个配置项就可以了。
连接数据库
操作流程要点
- 导入数据库包
- 打开数据库连接(connection),(MySQL)连接数据库服务器,数据库和后端同时设置服务器主机地址、端口、账号、密码、字符集等
- 生成游标(cursor)
- 在游标上执行(execute) sql 语句
- 非查询操作后需提交(commit)
- 所有操作完后需关闭(close) 游标和连接
cursor.execute(sql [, optional parameters]) # 注意这里是元组
cursor.executemany(sql, seq_of_parameters) # 注意这里是元组的列表
mysql
-
注意 sql 语句中的标点符号: 表名两侧加反单引号(`)
sql = "INSERT INTO `table` (`id`, `name`, `age`) VALUES (%s, %s, %s)"
-
命令行中输入 sql 指令,行末一定要加分号(;)
sql查询:
SELECT `subject` FROM table1 WHERE object = '大奔';
字符类型
枚举类型
在建表时通过枚举方式显式指定候选值
mysql> create table t1(gender enum('M', 'F'));
mysql> insert into t1 values('M'),('1'),('f'),(null);
mysql> select * from t1;
- 忽略大小写,第一个值对应下标1
set类型
建表时显式的设定候选值
可以一次插入多项,插入其他值则插入无效,插入重复值视为单个
- enum类似单选,set类似多选
这样,开发者对数据库的访问,从原来的使用底层的 sql 语句,变成 面向对象的开发,通过一系列对象的类定义 和方法调用就可以 操作数据库。通过 对象 操作数据库 的方法 被称之为 ORM。
优点
- 极大的简化了我们应用中的数据库开发,因为无需使用sql语句操作数据库了, 提高了开发的效率;
- 屏蔽了 不同的数据库访问的底层细节,基本做到了 开发好代码后,如果要换数据库,几乎不需要改代码, 修改几个配置项就可以了。
连接数据库
操作流程要点
- 导入数据库包
- 打开数据库连接(connection),(MySQL)连接数据库服务器,数据库和后端同时设置服务器主机地址、端口、账号、密码、字符集等
- 生成游标(cursor)
- 在游标上执行(execute) sql 语句
- 非查询操作后需提交(commit)
- 所有操作完后需关闭(close) 游标和连接
cursor.execute(sql [, optional parameters]) # 注意这里是元组
cursor.executemany(sql, seq_of_parameters) # 注意这里是元组的列表
mysql
-
注意 sql 语句中的标点符号: 表名两侧加反单引号(`)
sql = "INSERT INTO `table` (`id`, `name`, `age`) VALUES (%s, %s, %s)"
-
命令行中输入 sql 指令,行末一定要加分号(;)
sql查询:
SELECT `subject` FROM table1 WHERE object = '大奔';
字符类型
枚举类型
在建表时通过枚举方式显式指定候选值
mysql> create table t1(gender enum('M', 'F'));
mysql> insert into t1 values('M'),('1'),('f'),(null);
mysql> select * from t1;
- 忽略大小写,第一个值对应下标1
set类型
建表时显式的设定候选值
可以一次插入多项,插入其他值则插入无效,插入重复值视为单个
- enum类似单选,set类似多选