一、requests
Requests支持HTTP连接保持和连接池,支持使用cookie保持会话,支持文件上传,支持自动确定响应内容的编码,支持国际化的URL和 POST 数据自动编码。
基本GET请求(headers参数 和 parmas参数)
1.最基本的GET请求可以直接用get方法
response = requests.get("http://www.baidu.com/")
# 也可以这么写
# response = requests.request(
"get",
"http://www.baidu.com/"
)
response的常用方法:
- response.text 返回解码后的字符串(Requests 会基于 HTTP 响应的文本编码自动解码响应内容,大多数 Unicode 字符集都能被无缝地解码。)
- respones.content 以字节形式(二进制)返回。(返回的是服务器响应数据的原始二进制字节流,可以用来保存图片等二进制文件。)
- response.status_code 响应状态码
- response.request.headers 请求的请求头
- response.headers 响应头
- response.encoding = 'utf-8' 可以设置编码类型
- response.encoding 获取当前的编码
- response.json() 内置的JSON解码器,以json形式返回,前提返回的内容确保是json格式的,不然解析出错会抛异常
2. 添加 headers 和 查询参数
如果想添加 headers,可以传入headers参数来增加请求头中的headers信息。如果要将参数放在url中传递,可以利用 params 参数。
import requests
kw = {'wd':'长城'}
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"
}
# params 接收一个字典或者字符串的查询参数,
# 字典类型自动转换为url编码,不需要urlencode()
response = requests.get(
"http://www.baidu.com/s?",
params = kw,
headers = headers
)
# 查看响应内容,response.text 返回的是Unicode格式的数据
print (response.text)
# 查看响应内容,response.content返回的字节流数据
print (respones.content)
# 查看完整url地址
print (response.url)
# 查看响应头部字符编码
print (response.encoding)
# 查看响应码
print (response.status_code)
基本POST请求(data参数)
1. 最基本post方法
response = requests.post(url=url, data = data)
- url:post请求的目标url
- data:post请求的表单数据
2. 传入data数据 对于 POST 请求来说,我们一般需要为它增加一些参数。那么最基本的传参方法可以利用 data 这个参数。
import requests
req_url = "http://fanyi.youdao.com/translate?smartresult=dict&smartresult=rule&smartresult=ugc&sessionFrom=null"
#分析表单数据
formdata = {
'i': '老鼠爱大米',
'from': 'AUTO',
'to': 'AUTO',
'smartresult': 'dict',
'client': 'fanyideskweb',
'doctype': 'json',
'version': '2.1',
'keyfrom': 'fanyi.web',
'action': 'FY_BY_CLICKBUTTION',
'typoResult': 'false',
}
#添加请求头
req_header = {
'User-Agent':'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36',
}
response = requests.post(
req_url,
data = formdata,
headers = req_header
)
#print (response.text)
# 如果是json文件可以直接显示
print (response.json())
3.post请求上传文件
url = 'https://httpbin.org/post'
files = {'file': open('image.png', 'rb')}
response = requests.post(url, files=files)
print(response.text)
4.web客户端验证
需要添加 auth = (账户名, 密码)
import requests
auth=('test', '123456')
response = requests.get(
'http://192.168.199.107',
auth = auth
)
print (response.text)
5.设置代理(proxies参数
如果需要使用代理,你可以通过为任意请求方法提供 proxies 参数来配置单个请求:
import requests
# 根据协议类型,选择不同的代理
proxies = {
"http": "http://12.34.56.79:9527",
"https": "http://12.34.56.79:9527",
}
response = requests.get(
"http://www.baidu.com",
proxies = proxies
)
print(response.text)
6.私密代理验证(特定格式) 和 Web客户端验证(auth 参数) 私密代理
import requests
# 如果代理需要使用HTTP Basic Auth,可以使用下面这种格式:
proxy = {
"http": "name:[email protected]:16816"
}
response = requests.get(
"http://www.baidu.com",
proxies = proxy
)
print (response.text)
7.Cookies
import requests
response = requests.get("https://www.douban.com/")
# 7\. 返回CookieJar对象:
cookiejar = response.cookies
# 8\. 将CookieJar转为字典:
cookiedict = requests.utils.dict_from_cookiejar(
cookiejar
)
print (cookiejar)
print (cookiedict)
8.session
在 requests 里,session对象是一个非常常用的对象,这个对象代表一次用户会话:从客户端浏览器连接服务器开始,到客户端浏览器与服务器断开。
会话能让我们在跨请求时候保持某些参数,比如在同一个 Session 实例发出的所有请求之间保持 cookie
#模拟人人网登录
import requests
# 1\. 创建session对象,可以保存Cookie值
ssion = requests.session()
# 2\. 处理 headers
headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36"
}
# 3\. 需要登录的用户名和密码
data = {
"email":"18518753265",
"password":"ljh123456"
}
# 4\. 发送附带用户名和密码的请求,并获取登录后的Cookie值,保存在ssion里
ssion.post(
"http://www.renren.com/PLogin.do",
data = data
)
# 5\. ssion包含用户登录后的Cookie值,可以直接访问那些登录后才可以访问的页面
response = ssion.get(
"http://www.renren.com/965722397/profile"
)
# 6\. 打印响应内容
print (response.text)
9.处理HTTPS请求 SSL证书验证
Requests也可以为HTTPS请求验证SSL证书:
要想检查某个主机的SSL证书,你可以使用 verify 参数(也可以不写)
import requests
response = requests.get("https://www.baidu.com/", verify=True)
也可以省略不写
response = requests.get("https://www.baidu.com/")
print (r.text)
如果我们想跳过 12306 的证书验证,把 verify 设置为 False 就可以正常请求了。
import requests
response = requests.get("https://www.12306.cn/mormhweb/", verify = False)
print (response.text)
二、xpath
1.什么是XPath?
XPath (XML Path Language) 是一门在 XML 文档中查找信息的语言,可用来在 XML 文档中对元素和属性进行遍历。
2.什么是XML?
- XML 指可扩展标记语言(EXtensible Markup Language)
- XML 是一种标记语言,很类似 HTML
- XML 的设计宗旨是传输数据,而非显示数据
- XML 的标签需要我们自行定义。
- XML 被设计为具有自我描述性。
- XML 是 W3C 的推荐标准
3.选取节点
XPath 使用路径表达式来选取 XML 文档中的节点或者节点集。这些路径表达式和我们在常规的电脑文件系统中看到的表达式非常相似。
4.最常用的路径表达式:
表达式:描述
nodename:选取此节点的所有子节点。
/ :从根节点选取。
/ / : 从匹配选择的当前节点选择文档中的节点,而不考虑它们的位置。
. :选取当前节点。
.. :选取当前节点的父节点。
@ :选取属性。
路径表达式 结果
bookstore 选取 bookstore 元素的所有子节点。
/bookstore 选取根元素 bookstore。注释:假如路径起始于正斜杠( / ),则此路径始终代表到某元素的绝对路径!
bookstore/book 选取属于 bookstore 的子元素的所有 book 元素。
/ / book 选取所有 book 子元素,而不管它们在文档中的位置。
bookstore / / book 选择属于 bookstore 元素的后代的所有 book 元素,而不管它们位于 bookstore 之下的什么位置。
/ / @lang 选取名为 lang 的所有属性。
5.谓语(Predicates)
谓语用来查找某个特定的节点或者包含某个指定的值的节点,被嵌在方括号中。
路径表达式 结果
/bookstore/book[1] 选取属于 bookstore 子元素的第一个 book 元素。
/bookstore/book[last()] 选取属于 bookstore 子元素的最后一个 book 元素。
/bookstore/book[last()-1] 选取属于 bookstore 子元素的倒数第二个 book 元素。
/bookstore/book[position() < 3] 选取最前面的两个属于 bookstore 元素的子元素的 book 元素。
//title[@lang] 选取所有拥有名为 lang 的属性的 title 元素。
//title[@lang=’eng’] 选取所有 title 元素,且这些元素拥有值为 eng 的 lang 属性。
/bookstore/book[price>35.00] 选取 bookstore 元素的所有 book 元素,且其中的 price 元素的值须大于 35.00。
/bookstore/book[price>35.00]/title 选取 bookstore 元素中的 book 元素的所有 title 元素,且其中的 price 元素的值须大于 35.00。
6.选取未知节点
XPath 通配符可用来选取未知的 XML 元素
通配符 描述
* 匹配任何元素节点。
@* 匹配任何属性节点。
node() 匹配任何类型的节点。
路径表达式 结果
/bookstore/* 选取 bookstore 元素的所有子元素。
//* 选取文档中的所有元素。
html/node()/meta/@* 选择html下面任意节点下的meta节点的所有属性
//title[@*] 选取所有带有属性的 title 元素。
7.选取若干路径
通过在路径表达式中使用“|”运算符,您可以选取若干个路径
路径表达式 结果
//book/title | //book/price 选取 book 元素的所有 title 和 price 元素。
//title | //price 选取文档中的所有 title 和 price 元素。
/bookstore/book/title | //price 选取属于 bookstore 元素的 book 元素的所有 title 元素,以及文档中所有的 price 元素。
三、BeautifulSoup4
和 lxml 一样,Beautiful Soup 也是一个HTML/XML的解析器,主要的功能也是如何解析和提取 HTML/XML 数据
抓取工具 | 速度 | 使用难度 | 安装难度 |
---|---|---|---|
正则 | 最快 | 困难 | 无(内置) |
BeautifulSoup | 慢 | 最简单 | 简单 |
lxml | 快 | 简单 | 一般 |
四大对象种类
Beautiful Soup将复杂HTML文档转换成一个复杂的树形结构,每个节点都是Python对象,所有对象可以归纳为4种:
- Tag
- NavigableString
- BeautifulSoup
- Comment
1.Tag
Tag 通俗点讲就是 HTML 中的一个个标签
#创建 Beautiful Soup 对象
soup = BeautifulSoup(html)
print(soup.title)
# The Dormouse's story
print(soup.head)
# The Dormouse's story
print(soup.a)
#
print(soup.p)
# The Dormouse's story
print(type(soup.p))
#
对于 Tag,它有两个重要的属性,是 name 和 attrs
print(soup.name)
# [document] #soup 对象本身比较特殊,它的 name 即为 [document]
print (soup.head.name)
# head #对于其他内部标签,输出的值便为标签本身的名称
print (soup.p.attrs)
# {'class': ['title'], 'name': 'dromouse'}
# 在这里,我们把 p 标签的所有属性打印输出了出来,得到的类型是一个字典。
print (soup.p['class'] # soup.p.get('class'))
# ['title'] #还可以利用get方法,传入属性的名称,二者是等价的
soup.p['class'] = "newClass"
print soup.p # 可以对这些属性和内容等等进行修改
# The Dormouse's story
2. NavigableString
取标签内部的文字用 .string 即可,例如
print (soup.p.string)
# The Dormouse's story
print (type(soup.p.string))
# In [13]:
3. BeautifulSoup BeautifulSoup 对象表示的是一个文档的内容。大部分时候,可以把它当作 Tag 对象,是一个特殊的 Tag,我们可以分别获取它的类型,名称,以及属性来感受一下
print type(soup.name)
#
print soup.name
# [document]
print soup.attrs # 文档本身的属性为空
# {}
4. Comment Comment 对象是一个特殊类型的 NavigableString 对象,其输出的内容不包括注释符号。
print soup.a
#
print soup.a.string
# Elsie
print type(soup.a.string)
#
# a标签里的内容实际上是注释,但是如果我们利用 .string 来输出它的内容时,注释符号已经去掉了。
四、selenium
1.Selenium是一个Web的自动化测试工具;
2.Selenium 可以根据我们的指令,让浏览器自动加载页面,获取需要的数据,甚至页面截屏,或者判断网站上某些动作是否发生;
3.Selenium 自己不带浏览器,不支持浏览器的功能,它需要与第三方浏览器结合在一起才能使用。但是我们有时候需要让它内嵌在代码中运行,所以我们可以用一个叫 PhantomJS 的工具代替真实的浏览器;
4.Selenium 库里有个叫 WebDriver 的 API。WebDriver 有点儿像可以加载网站的浏览器,但是它也可以像 BeautifulSoup 或者其他 Selector 对象一样用来查找页面元素,与页面上的元素进行交互 (发送文本、点击等),以及执行其他动作来运行网络爬虫。
主要使用的方法和代码如下:
from selenium import webdriver
import time
from selenium.webdriver.support.ui import WebDriverWait
from selenium.common.exceptions import NoSuchElementException,TimeoutException
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
# 要想调用键盘按键操作需要引入keys包
from selenium.webdriver.common.keys import Keys
# 加载网页(使用火狐浏览器加载)
# driver = webdriver.Firefox(executable_path='/home/ljh/桌面/driver/geckodriver')
# driver.get('https://www.baidu.com/')
# 加载网页(使用无头浏览器加载)
# driver = webdriver.PhantomJS(executable_path='/home/ljh/桌面/driver/phantomjs')
# driver.get('https://www.baidu.com/')
# 加载网页(使用谷歌浏览器加载)
# 创建chrome参数对象
# opt = webdriver.ChromeOptions()
# 把chrome设置成为无界面模式
# opt.set_headless()
# driver = webdriver.Chrome(
options=opt, executable_path='/Users/ljh/Desktop/chromedriver'
)
driver = webdriver.Chrome(executable_path='/home/ljh/桌面/driver/chromedriver')
#设置页面的加载超时时间
driver.set_page_load_timeout(0.1)
#处理异常
try:
driver.get('https://www.baidu.com/')
driver.save_screenshot('prcture.png')
except TimeoutException as err:
print(err)
#定位和操作
# driver.find_element_by_xpath():根据xpath定位节点
# driver.find_element_by_class_name():根据类名定位节点
# driver.find_element_by_partial_link_text():根据部分文本内容定位节点
# driver.find_element_by_css_selector():根据css选择器定位节点
# driver.find_element_by_link_text():根据完整文本定位节点
driver.find_element_by_id('kw').send_keys('隔壁老赵')
driver.find_element_by_id('su').click()
#获取信息
print(len(driver.page_source))
print(driver.get_cookies())
print(driver.current_url)
print(driver.name)
#清空输入框内容
driver.find_element_by_id('kw').clear()
#输入框重新输入内容
driver.find_element_by_id('kw').send_keys('风景')
#模拟回车键
driver.find_element_by_id('su').send_keys(Keys.RETURN)
#获取当前的url
#截取网页页面(生成当前的页面快照并保存)
driver.save_screenshot('baidu.png')
#前进和后退
time.sleep(2)
driver.back() #后退
time.sleep(2)
driver.forward() #前进
#获取属性和获取文本
time.sleep(2)
href = driver.find_element_by_xpath('//h3[@class="t"]/a').get_attribute('href')
title = driver.find_element_by_xpath('//h3[@class="t"]/a').text
print(href)
print(title)
#关于cookie相关操作
cookies_dict = {cookie['name']:cookie['value'] for cookie in driver.get_cookies()}
print(cookies_dict)
print(driver.get_cookie('BIDUPSID'))
# driver.delete_all_cookies()
# driver.delete_cookie()
# driver.add_cookie()
###页面等待
# 因为selenium加载的页面和浏览器一样会渲染页面,并且有些网页加载需要消耗时间
# ,这时在页面加载出来之前去寻找节点的话,会报异常,所有我们需要添加等待,有时甚至
# 需要前置等待
#
# 强制等待
# time.sleep(5)
#
# 隐士等待(设置等待时间)
# driver.implicitly_wait(10)
# 是指显示等待:设置最大的等待时间
# 直到某一条件成立然后继续执行
# WebDriverWait(driver,10).until(EC.presence_of_element_located(By.ID,''))
#退出
driver.close() #退出当前页面
driver.quit() #退出浏览器
1.页面的相关操作:
- 获取id标签值
element = driver.find_element_by_id("passwd-id")
- 获取name标签值
element = driver.find_element_by_name("user-name")
- 获取标签名值
element = driver.find_elements_by_tag_name("input")
- 也可以通过XPath来匹配
element = driver.find_element_by_xpath("//input[@id='passwd-id']")
定位UI元素 (WebElements)
- find_element_by_id
find_elements_by_name
find_elements_by_xpath
find_elements_by_link_text
find_elements_by_partial_link_text
find_elements_by_tag_name
find_elements_by_class_name
find_elements_by_css_selector
页面前进和后退
- 操作页面的前进和后退功能:
driver.forward() #前进
driver.back() # 后退
Cookies操作
- 获取页面每个Cookies值,用法如下
cookies = driver.get_cookies()
cookie_dict = {i['name']:i['value'] for i in cookies}
print(cookie_dict)
添加cookies
driver.add_cookie(cookie_dict)
删除Cookies,用法如下
- 删除一个特定的cookie
driver.delete_cookie("CookieName")
- 删除所有cookie
driver.delete_all_cookies()
设置无头浏览器
opt = webdriver.ChromeOptions()
opt.set_headless()
设置代理
opt = webdriver.ChromeOptions()
opt.add_argument("--proxy-server=http://118.20.16.82:9999")
(选项卡管理)页面切换
- 一个浏览器肯定会有很多窗口,所以我们肯定要有方法来实现窗口的切换。切换窗口的方法如下:
js = 'window.open("http://www.baidu.com/")'
driver.execute_script(js)
driver.switch_to.window(driver.window_handles[0])
- 也可以使用 window_handles 方法来获取每个窗口的操作对象。例如:
for handle in driver.window_handles:
driver.switch_to_window(handle)
切换Frame
- 网页中有一种节点叫做iframe,也就是子Frame,我们不能够直接获取到子Frame中的节点,要想获取到需要切换到子frame下
login_frame:为子frame的名称
driver.switch_to_frame('login_frame')
鼠标动作链
#-*- coding:UTF-8 -*-
##### 导入ActionChains类
from selenium.webdriver import ActionChains
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
import time
driver = webdriver.Chrome(executable_path='/Users/ljh/Desktop/chromedriver')
driver.get('http://www.baidu.com')
##### 鼠标移动到ac位置,移动到第四个a标签的位置
action = driver.find_element_by_xpath('//div[@id="u1"]/a[4]')
ActionChains(driver).move_to_element(action).perform()
##### 在action上单击
ActionChains(driver).move_to_element(action).click(action).perform()
##### 在 ac 位置双击
ActionChains(driver).move_to_element(action).double_click(action).perform()
##### 在 ac 位置右击
ActionChains(driver).move_to_element(action).context_click(action).perform()
##### 在 ac 位置左键单击hold住
ActionChains(driver).move_to_element(action).click_and_hold(action).perform()
##### 将 ac1 拖拽到 ac2 位置
time.sleep(5)
ac1 = driver.find_element_by_id("su")
ac2 = driver.find_element_by_class_name('mnav')
ActionChains(driver).drag_and_drop(ac1,ac2).perform()
time.sleep(5)
driver.quit()
2.页面等待
- 隐式等待是等待特定的时间,如果节点没有立即出现,隐士等待将一段时间再进行查找
- 显式等待是指定一个最长的等待时间,直到条件成立时继续执行。如果在设定时间内没加载出来节点,则返回异常信息,如果加载出来了则返回节点
隐式等待
from selenium import webdriver
driver = webdriver.Chrome()
driver.implicitly_wait(10) # seconds
driver.get("http://www.xxxxx.com/loading")
myDynamicElement = driver.find_element_by_id("myDynamicElement")
显式等待
显式等待指定某个条件,然后设置最长等待时间。如果在这个时间还没有找到元素,那么便会抛出异常了。
from selenium import webdriver
from selenium.webdriver.common.by import By
# WebDriverWait 库,负责循环等待
from selenium.webdriver.support.ui import WebDriverWait
# expected_conditions 类,负责条件出发
from selenium.webdriver.support import expected_conditions as EC
driver = webdriver.Chrome()
driver.get("http://www.xxxxx.com/loading")
try:
##### 会在这里等待,如果10秒内 id="myDynamicElement"的标签出现
则返回,如果不出现则报异常
element = WebDriverWait(driver, 10).until(
EC.presence_of_element_located(
(By.ID, "myDynamicElement")
)
)
finally:
driver.quit()
3.异常处理
请求超时异常处理
from selenium.common.exceptions import TimeoutException
try:
brower.get(url)
except TimeoutException:
print('Time out')
找不到标签的异常处理
from selenium.common.exceptions import NoSuchElementException
try:
brower.find_element_by_id('').click()
print('有标签')
except NoSuchElementException:
print('没有这个标签')
4.执行JavaScript语句
### js隐藏元素,将获取的图片元素隐藏
imgs = driver.find_elements_by_xpath("//img")
for img in imgs:
driver.execute_script('$(arguments[0]).fadeOut()',img)
#### 向下滚动到页面底部
driver.execute_script('window.scrollTo(0,document.body.scrollHeight)')
#### 弹出弹窗
driver.execute_script('alert("This is a alert")')
driver.quit()
五、Pyquery
pyquery相当于jQuery的python实现,可以用于解析HTML网页等。
1、初始化
有 4 种方法可以进行初始化: 可以通过传入 字符串、lxml、文件 或者 url 来使用PyQuery。
from pyquery import PyQuery as pq
from lxml import etree
#传入字符串
d = pq("")
#传入lxml
d = pq(etree.fromstring(""))
#传入url
d = pq(url='http://google.com/')
#传入文件
d = pq(filename=path_to_html_file)
现在,d 就像 jQuery 中的 $ 一样了。
2、.html()和.text() 获取相应的 HTML 块或者文本内容,
p=pq("Hello World! ")
# 获取相应的 HTML 块
print (p('head').html())
# 获取相应的文本内容
print (p('head').text())
输出:
'''
hello Word
Hello World!
'''
3、(selector):通过选择器来获取目标内容,
d = pq(
"test 1
test 2
"
)
# 获取 元素内的 HTML 块
print (d('div').html())
# 获取 id 为 item-0 的元素内的文本内容
print (d('#item-0').text())
# 获取 class 为 item-1 的元素的文本内容
print (d('.item-1').text())
'''输出:
test 1
test 2
test 1
test 2
'''
4、.eq(index):根据索引号获取指定元素(index 从 0 开始)
d = pq(
"test 1
test 2
"
)
# 获取第二个 p 元素的文本内容
print (d('p').eq(1).text())
'''输出
test 2
'''
5、.find():查找嵌套元素,
d = pq("test 1
test 2
")
# 查找 内的 p 元素
print d('div').find('p')
# 查找 内的 p 元素,输出第一个 p 元素
print d('div').find('p').eq(0)
'''输出:
test 1
test 2
test 1
'''
6、.filter():根据 class、id 筛选指定元素,
d = pq("test 1
test 2
")
# 查找 class 为 item-1 的 p 元素
print d('p').filter('.item-1')
# 查找 id 为 item-0 的 p 元素
print d('p').filter('#item-0')
'''输出:
test 2
test 1
'''
7、.attr():获取、修改属性值,
d = pq("test 1
test 2")
# 获取 标签的属性 id
print(d('p').attr('id'))
# 修改 标签的 class 属性为 new
print(d('a').attr('class','new'))
'''输出:
item-0
test 2
'''
8、其他操作:
#添加 class
.addClass(value):
#判断是否包含指定的 class,返回 True 或 False
.hasClass(value):
#获取子元素
.children():
#获取父元素
.parents():
#获取下一个元素
.next():
#获取后面全部元素块
.nextAll():
#获取所有不匹配该选择器的元素
.not_(selector):
六、re
1.compile 函数
compile 函数用于编译正则表达式,生成一个 Pattern 对象
import re
**将正则表达式编译成 Pattern 对象**
pattern = re.compile(r'\d+')
修饰符号
描述
re.I
使用匹配对大小写不敏感(不区分大小写
re.S
使.匹配包括换行符在内的所有字符
re.M
多行匹配
re.L
做本地化识别
一些常用方法:
- match 方法:从起始位置开始查找,一次匹配
- search 方法:从任何位置开始查找,一次匹配
- findall 方法:全部匹配,返回列表
- finditer 方法:全部匹配,返回迭代器
- split 方法:分割字符串,返回列表
- sub 方法:替换
1.match方法介绍
match 方法用于查找字符串的头部(也可以指定起始位置),它是一次匹配,只要找到了一个匹配的结果就返回,而不是查找所有匹配的结果。它的一般使用形式如下:
当匹配成功时,返回一个 Match 对象,如果没有匹配上,则返回 None
import re
# 使用match方法进行匹配操作
result = re.match(正则表达式,要匹配的字符串)
# 如果上一步匹配到数据的话,可以使用group方法来提取数据
result.group()
总结:能够匹配出以XXX开头的字符串
为1次匹配
不符合正则规律就返回None
七、多线程
1.多任务的概念
简单地说,就是操作系统可以同时运行多个任务
并发:指的是任务数多余cpu核数,通过操作系统的各种任务调度算法,实现用多个任务“一起”执行(实际上总有一些任务不在执行,因为切换任务的速度相当快,看上去一起执行而已)
并行:指的是任务数小于等于cpu核数,即任务真的是一起执行的
2.线程
python的thread模块是比较底层的模块,python的threading模块是对thread做了一些包装的,可以更加方便的被使用
单线程
#coding=utf-8
import time
def saySorry():
for i in range(5):
print("亲爱的,我错了,我能吃饭了吗?")
time.sleep(1)
def do():
for i in range(5):
print("亲爱的,我错了,我给你按摩")
time.sleep(1)
if __name__ == "__main__":
saySorry()
saydo()
多线程
#coding=utf-8
import threading
import time
def saySorry():
for i in range(5):
print("亲爱的,我错了,我能吃饭了吗?")
time.sleep(1)
def do():
for i in range(5):
print("亲爱的,我错了,我给你按摩")
time.sleep(1)
if __name__ == "__main__":
td1 = threading.Thread(target=saySorry)
td1.start() #启动线程,即让线程开始执行
td2 = threading.Thread(target=saySorry)
td2.start() #启动线程,即让线程开始执行
hreading.Thread参数介绍
- target:线程执行的函数
- name:线程名称
- args:执行函数中需要传递的参数,元组类型 另外:注意daemon参数
- 如果某个子线程的daemon属性为False,主线程结束时会检测该子线程是否结束,如果该子线程还在运行,则主线程会等待它完成后再退出;
- 如果某个子线程的daemon属性为True,主线程运行结束时不对这个子线程进行检查而直接退出,同时所有daemon值为True的子线程将随主线程一起结束,而不论是否运行完成。
- 属性daemon的值默认为False,如果需要修改,必须在调用start()方法启动线程之前进行设置
2.主线程与子线程的执行顺序
#coding=utf-8
import threading
from time import sleep,ctime
def sing():
for i in range(3):
print("正在唱歌...%d"%i)
sleep(1)
def dance():
for i in range(3):
print("正在跳舞...%d"%i)
sleep(1)
if __name__ == '__main__':
print('---开始---:%s'%ctime())
t1 = threading.Thread(target=sing)
t2 = threading.Thread(target=dance)
t1.start()
t2.start()
t1.join()
t2.join()
#sleep(5) # 屏蔽此行代码,试试看,程序是否会立马结束?
(会立即结束)
print('---结束---:%s'%ctime())
线程-注意点
- 线程执行代码的封装 通过上一小节,能够看出,通过使用threading模块能完成多任务的程序开发,为了让每个线程的封装性更完美,所以使用threading模块时,往往会定义一个新的子类class,只要继承threading.Thread就可以了,然后重写run方法
#coding=utf-8
import threading
import time
class MyThread(threading.Thread):
def run(self):
for i in range(3):
time.sleep(1)
msg = "I'm "+self.name+' @ '+str(i) #name属性中保存的是当前线程的名字
print(msg)
if __name__ == '__main__':
t = MyThread()
t.start()
说明
python的threading.Thread类有一个run方法,用于定义线程的功能函数,可以在自己的线程类中覆盖该方法。而创建自己的线程实例后,通过Thread类的start方法,可以启动该线程,交给python虚拟机进行调度,当该线程获得执行的机会时,就会调用run方法执行线程。
3.线程的执行顺序
#coding=utf-8
import threading
import time
class MyThread(threading.Thread):
def run(self):
for i in range(3):
time.sleep(1)
msg = "I'm "+self.name+' @ '+str(i)
print(msg)
def test():
for i in range(5):
t = MyThread()
t.start()
if __name__ == '__main__':
test()
说明
- 从代码和执行结果我们可以看出,多线程程序的执行顺序是不确定的。当执行到sleep语句时,线程将被阻塞(Blocked),到sleep结束后,线程进入就绪(Runnable)状态,等待调度。而线程调度将自行选择一个线程执行。上面的代码中只能保证每个线程都运行完整个run函数,但是线程的启动顺序、run函数中每次循环的执行顺序都不能确定。
总结
- 每个线程默认有一个名字,尽管上面的例子中没有指定线程对象的name,但是python会自动为线程指定一个名字。
- 当线程的run()方法结束时该线程完成。
- 无法控制线程调度程序,但可以通过别的方式来影响线程调度的方式。
4.多线程-共享全局变量
from threading import Thread
import time
g_num = 100
def work1():
global g_num
for i in range(3):
g_num += 1
print("----in work1, g_num is %d---"%g_num)
def work2():
global g_num
print("----in work2, g_num is %d---"%g_num)
print("---线程创建之前g_num is %d---"%g_num)
t1 = Thread(target=work1)
t1.start()
#延时一会,保证t1线程中的事情做完
time.sleep(1)
t2 = Thread(target=work2)
t2.start()
---线程创建之前g_num is 100---
----in work1, g_num is 103---
----in work2, g_num is 103---
5.元组当做实参传递到线程中
from threading import Thread
import time
def work1(nums):
nums.append(44)
print("----in work1---",nums)
def work2(nums):
#延时一会,保证t1线程中的事情做完
time.sleep(1)
print("----in work2---",nums)
g_nums = [11,22,33]
t1 = Thread(target=work1, args=(g_nums,))
t1.start()
t2 = Thread(target=work2, args=(g_nums,))
t2.start()
----in work1--- [11, 22, 33, 44]
----in work2--- [11, 22, 33, 44]
总结:
- 在一个进程内的所有线程共享全局变量,很方便在多个线程间共享数据
- 缺点就是,线程是对全局变量随意遂改可能造成多线程之间对全局变量的混乱(即线程非安全)
6.互斥锁(重点)
当多个线程几乎同时修改某一个共享数据的时候,需要进行同步控制
线程同步能够保证多个线程安全访问竞争资源,最简单的同步机制是引入互斥锁。
互斥锁为资源引入一个状态:锁定/非锁定
某个线程要更改共享数据时,先将其锁定,此时资源的状态为“锁定”,其他线程不能更改;直到该线程释放资源,将资源的状态变成“非锁定”,其他的线程才能再次锁定该资源。互斥锁保证了每次只有一个线程进行写入操作,从而保证了多线程情况下数据的正确性。
# 创建锁
mutex = threading.Lock()
# 锁定
mutex.acquire()
# 释放
mutex.release()
注意:
- 如果这个锁之前是没有上锁的,那么acquire不会堵塞
- 如果在调用acquire对这个锁上锁之前 它已经被 其他线程上了锁,那么此时acquire会堵塞,直到这个锁被解锁为止
使用互斥锁完成2个线程对同一个全局变量各加100万次的操作
import threading
import time
g_num = 0
def test1(num):
global g_num
for i in range(num):
mutex.acquire() # 上锁
g_num += 1
mutex.release() # 解锁
print("---test1---g_num=%d"%g_num)
def test2(num):
global g_num
for i in range(num):
mutex.acquire() # 上锁
g_num += 1
mutex.release() # 解锁
print("---test2---g_num=%d"%g_num)
# 创建一个互斥锁
# 默认是未上锁的状态
mutex = threading.Lock()
# 创建2个线程,让他们各自对g_num加1000000次
p1 = threading.Thread(target=test1, args=(1000000,))
p1.start()
p2 = threading.Thread(target=test2, args=(1000000,))
p2.start()
p1.join()
p2.join()
print("2个线程对同一个全局变量操作之后的最终结果是:%s" % g_num)
2个线程对同一个全局变量操作之后的最终结果是:2000000
上锁解锁过程
- 当一个线程调用锁的acquire()方法获得锁时,锁就进入“locked”状态。
- 每次只有一个线程可以获得锁。如果此时另一个线程试图获得这个锁,该线程就会变为“blocked”状态,称为“阻塞”,直到拥有锁的线程调用锁的release()方法释放锁之后,锁进入“unlocked”状态。
- 线程调度程序从处于同步阻塞状态的线程中选择一个来获得锁,并使得该线程进入运行(running)状态。
总结:
锁的好处:
- 确保了某段关键代码只能由一个线程从头到尾完整地执行
锁的坏处:
- 阻止了多线程并发执行,包含锁的某段代码实际上只能以单线程模式执行,效率就大大地下降了
- 由于可以存在多个锁,不同的线程持有不同的锁,并试图获取对方持有的锁时,可能会造成死锁
死锁问题
在线程间共享多个资源的时候,如果两个线程分别占有一部分资源并且同时等待对方的资源,就会造成死锁。
#coding=utf-8
import threading
import time
class MyThread1(threading.Thread):
def run(self):
# 对mutexA上锁
mutexA.acquire()
# mutexA上锁后,延时1秒,等待另外那个线程 把mutexB上锁
print(self.name+'----do1---up----')
time.sleep(1)
# 此时会堵塞,因为这个mutexB已经被另外的线程抢先上锁了
mutexB.acquire()
print(self.name+'----do1---down----')
mutexB.release()
# 对mutexA解锁
mutexA.release()
class MyThread2(threading.Thread):
def run(self):
# 对mutexB上锁
mutexB.acquire()
# mutexB上锁后,延时1秒,等待另外那个线程 把mutexA上锁
print(self.name+'----do2---up----')
time.sleep(1)
# 此时会堵塞,因为这个mutexA已经被另外的线程抢先上锁了
mutexA.acquire()
print(self.name+'----do2---down----')
mutexA.release()
# 对mutexB解锁
mutexB.release()
mutexA = threading.Lock()
mutexB = threading.Lock()
if __name__ == '__main__':
t1 = MyThread1()
t2 = MyThread2()
t1.start()
t2.start()
八、多进程
1. 什么是进程
程序:例如xxx.py这是程序,是一个静态的
进程:一个程序运行起来后,代码+用到的资源 称之为进程,它是操作系统分配资源的基本单元。
不仅可以通过线程完成多任务,进程也是可以的
2.进程的创建-multiprocessing
# -*- coding:utf-8 -*-
from multiprocessing import Process
import time
def run_proc():
"""子进程要执行的代码"""
while True:
print("----2----")
time.sleep(1)
if __name__=='__main__':
p = Process(target=run_proc)
p.start()
while True:
print("----1----")
time.sleep(1)
说明:创建子进程时,只需要传入一个执行函数和函数的参数,创建一个Process实例,用start()方法启动
3.进程pid
# -*- coding:utf-8 -*-
from multiprocessing import Process
import os
import time
def run_proc():
"""子进程要执行的代码"""
print('子进程运行中,pid=%d...' % os.getpid()) # os.getpid获取当前进程的进程号
print('子进程将要结束...')
if __name__ == '__main__':
print('父进程pid: %d' % os.getpid()) # os.getpid获取当前进程的进程号
p = Process(target=run_proc)
print(p.name)
p.start()
#可以获取所有进程,三方包需要安装才能使用
import psutil
pids = psutil.pids()
for pid in pids:
p = psutil.Process(pid)
print("pid-%d,pname-%s" %(pid,p.name()))
4.Process参数
Process(group, target, name, args , kwargs)
- target:如果传递了函数的引用,可以任务这个子进程就执行这里的代码
- args:给target指定的函数传递的参数,以元组的方式传递
- kwargs:给target指定的函数传递命名参数
- name:给进程设定一个名字,可以不设定
- group:指定进程组,大多数情况下用不到
Process创建的实例对象的常用方法:
- start():启动子进程实例(创建子进程)
- is_alive():判断进程子进程是否还在活着
- join([timeout]):是否等待子进程执行结束,或等待多少秒
- terminate():不管任务是否完成,立即终止子进程
Process创建的实例对象的常用属性:
- name:当前进程的别名,默认为Process-N,N为从1开始递增的整数
- pid:当前进程的pid(进程号)
给子进程指定的函数传递参数
# -*- coding:utf-8 -*-
from multiprocessing import Process
import os
from time import sleep
def run_proc(name, age, **kwargs):
for i in range(10):
print('子进程运行中,name= %s,age=%d ,pid=%d...' % (name, age, os.getpid()))
print(kwargs)
sleep(0.2)
if __name__=='__main__':
p = Process(target=run_proc, args=('test',18), kwargs={"m":20})
p.start()
sleep(1) # 1秒中之后,立即结束子进程
p.terminate()
p.join()
运行结果:
子进程运行中,name= test,age=18 ,pid=45097...
{'m': 20}
子进程运行中,name= test,age=18 ,pid=45097...
{'m': 20}
子进程运行中,name= test,age=18 ,pid=45097...
{'m': 20}
子进程运行中,name= test,age=18 ,pid=45097...
{'m': 20}
子进程运行中,name= test,age=18 ,pid=45097...
{'m': 20}
5. 进程间不同享全局变量
# -*- coding:utf-8 -*-
from multiprocessing import Process
import os
import time
nums = [11, 22]
def work1():
"""子进程要执行的代码"""
print("in process1 pid=%d ,nums=%s" % (os.getpid(), nums))
for i in range(3):
nums.append(i)
time.sleep(1)
print("in process1 pid=%d ,nums=%s" % (os.getpid(), nums))
def work2():
"""子进程要执行的代码"""
print("in process2 pid=%d ,nums=%s" % (os.getpid(), nums))
if __name__ == '__main__':
p1 = Process(target=work1)
p1.start()
p1.join()
p2 = Process(target=work2)
p2.start()
运行结果:
in process1 pid=11349 ,nums=[11, 22]
in process1 pid=11349 ,nums=[11, 22, 0]
in process1 pid=11349 ,nums=[11, 22, 0, 1]
in process1 pid=11349 ,nums=[11, 22, 0, 1, 2]
in process2 pid=11350 ,nums=[11, 22]
6.进程间通信-Queue
- Queue的使用 可以使用multiprocessing模块的Queue实现多进程之间的数据传递,Queue本身是一个消息列队程序,
#coding=utf-8
from multiprocessing import Queue
q=Queue(3) #初始化一个Queue对象,最多可接收三条put消息
q.put("消息1")
q.put("消息2")
print(q.full()) #False
q.put("消息3")
print(q.full()) #True
#因为消息列队已满下面的try都会抛出异常,第一个try会等待2秒后再抛出异常,第二个Try会立刻抛出异常
try:
q.put("消息4",True,2)
except:
print("消息列队已满,现有消息数量:%s"%q.qsize())
try:
q.put_nowait("消息4")
except:
print("消息列队已满,现有消息数量:%s"%q.qsize())
#推荐的方式,先判断消息列队是否已满,再写入
if not q.full():
q.put_nowait("消息4")
#读取消息时,先判断消息列队是否为空,再读取
if not q.empty():
for i in range(q.qsize()):
print(q.get_nowait())
运行结果:
False
True
消息列队已满,现有消息数量:3
消息列队已满,现有消息数量:3
消息1
消息2
消息3
说明
初始化Queue()对象时(例如:q=Queue()),若括号中没有指定最大可接收的消息数量,或数量为负值,那么就代表可接受的消息数量没有上限(直到内存的尽头);
- Queue.qsize():返回当前队列包含的消息数量;
- Queue.empty():如果队列为空,返回True,反之False ;
- Queue.full():如果队列满了,返回True,反之False;
- Queue.get(block, timeout):获取队列中的一条消息,然后将其从列队中移除,block默认值为True;
- Queue.get_nowait():相当Queue.get(False);
- Queue.put(item,block,timeout):将item消息写入队列,block默认值为True;
- Queue.put_nowait(item):相当Queue.put(item, False);
7. Queue实例以及在多进程间的使用
from multiprocessing import Process, Queue
import os, time, random
# 写数据进程执行的代码:
def write(q):
for value in ['A', 'B', 'C', 'D', 'E']:
print('Put %s to queue...' % value)
q.put(value)
time.sleep(random.random())
# 读数据进程执行的代码:
def read(q):
while True:
if not q.empty():
value = q.get(True)
print('Get %s from queue.' % value)
time.sleep(random.random())
else:
break
if __name__=='__main__':
# 父进程创建Queue,并传给各个子进程:
q = Queue()
pw = Process(target=write, args=(q,))
pr = Process(target=read, args=(q,))
# 启动子进程pw,写入:
pw.start()
# 等待pw结束:
pw.join()
# 启动子进程pr,读取:
pr.start()
pr.join()
print('所有数据都写入并且读完')
8.进程池Pool
当需要创建的子进程数量不多时,可以直接利用multiprocessing中的Process动态成生多个进程,但如果是上百甚至上千个目标,手动的去创建进程的工作量巨大,此时就可以用到multiprocessing模块提供的Pool方法。
初始化Pool时,可以指定一个最大进程数,当有新的请求提交到Pool中时,如果池还没有满,那么就会创建一个新的进程用来执行该请求;但如果池中的进程数已经达到指定的最大值,那么该请求就会等待,直到池中有进程结束,才会用之前的进程来执行新的任务,请看下面的实例:
# -*- coding:utf-8 -*-
from multiprocessing import Pool
import os, time, random
def worker(msg):
t_start = time.time()
print("%s开始执行,进程号为%d" % (msg,os.getpid()))
# random.random()随机生成0~1之间的浮点数
time.sleep(random.random()*2)
t_stop = time.time()
print(msg,"执行完毕,耗时%0.2f" % (t_stop-t_start))
po = Pool(3) # 定义一个进程池,最大进程数3
for i in range(0,10):
# Pool().apply_async(要调用的目标,(传递给目标的参数元祖,))
# 每次循环将会用空闲出来的子进程去调用目标
po.apply_async(worker,(i,))
print("----start----")
po.close() # 关闭进程池,关闭后po(进程池)不再接收新任务
po.join() # 等待po(进程池)中所有子进程执行完成,必须放在close语句之后
print("-----end-----")
运行结果:
----start----
0开始执行,进程号为21466
1开始执行,进程号为21468
2开始执行,进程号为21467
0 执行完毕,耗时1.01
3开始执行,进程号为21466
2 执行完毕,耗时1.24
4开始执行,进程号为21467
3 执行完毕,耗时0.56
5开始执行,进程号为21466
1 执行完毕,耗时1.68
6开始执行,进程号为21468
4 执行完毕,耗时0.67
7开始执行,进程号为21467
5 执行完毕,耗时0.83
8开始执行,进程号为21466
6 执行完毕,耗时0.75
9开始执行,进程号为21468
7 执行完毕,耗时1.03
8 执行完毕,耗时1.05
9 执行完毕,耗时1.69
-----end-----
multiprocessing.Pool常用函数解析:
- apply_async(func[, args[, kwds]]) :使用非阻塞方式调用func(并行执行,堵塞方式必须等待上一个进程退出才能执行下一个进程),args为传递给func的参数列表,kwds为传递给func的关键字参数列表;
- close():关闭Pool,使其不再接受新的任务;
- terminate():不管任务是否完成,立即终止;
- join():主进程阻塞,等待子进程的退出, 必须在close或terminate之后使用;
进程池中中进程通信Manager().Queue()
如果要使用Pool创建进程,就需要使用multiprocessing.Manager()中的Queue(),而不是multiprocessing.Queue(),否则会得到一条如下的错误信息:
RuntimeError: Queue objects should only be shared between processes through inheritance.
# -*- coding:utf-8 -*-
# 修改import中的Queue为Manager
from multiprocessing import Manager,Pool
import os,time,random
def writer(q):
print("writer启动(%s),父进程为(%s)" % (os.getpid(), os.getppid()))
for i in "beicai1804":
q.put(i)
def reader(q):
print("reader启动(%s),父进程为(%s)" % (os.getpid(), os.getppid()))
for i in range(q.qsize()):
print("reader从Queue获取到消息:%s" % q.get(True))
if __name__=="__main__":
print("(%s) start" % os.getpid())
q = Manager().Queue() # 使用Manager中的Queue
po = Pool()
po.apply_async(writer, (q,))
time.sleep(1) # 先让上面的任务向Queue存入数据,然后再让下面的任务开始从中取数据
po.apply_async(reader, (q,))
po.close()
po.join()
print("(%s) End" % os.getpid())
运行结果:
(11095) start
writer启动(11097),父进程为(11095)
reader启动(11098),父进程为(11095)
reader从Queue获取到消息:b
reader从Queue获取到消息:e
reader从Queue获取到消息:i
reader从Queue获取到消息:c
reader从Queue获取到消息:a
reader从Queue获取到消息:i
......
(11095) End
进程与线程的对比:
进程、线程对比
功能
- 进程,能够完成多任务,比如 在一台电脑上能够同时运行多个QQ
- 线程,能够完成多任务,比如 一个QQ中的多个聊天窗口
定义的不同
- 进程是系统进行资源分配基本单位.
- 线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.
- 线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享所在进程所拥有的全部资源
区别
- 一个程序至少有一个进程,一个进程至少有一个线程.
- 线程的划分尺度小于进程(资源比进程少),使得多线程程序的并发性高。
- 进程在执行过程中拥有独立的内存单元,而多个线程共享内存,从而极大地提高了程序的运行
效率
- 线线程不能够独立执行,必须依存在进程中
优缺点
- 线程和进程在使用上各有优缺点:线程执行开销小,但不利于资源的管理和保护;而进程正相反。
使用场景:
多进程常用来处理计算密集型任务: 计算密集型任务的特点:是要进行大量的计算,消耗CPU资源,比如计算圆周率、对视频进行高清解码等等,全靠CPU的运算能力。计算密集型任务可以用多任务完成,但是任务越多,花在任务切换的时间就越多,CPU执行任务的效率就越低,所以,要最高效地利用CPU,计算密集型任务同时进行的数量应当等于CPU的核心数。
多线程常用来处理IO密集型任务: IO密集型:涉及到网络、磁盘IO的任务都是IO密集型任务,特点是CPU消耗很少,任务的大部分时间都在等待IO操作完成(因为IO的速度远远低于CPU和内存的速度)。但是也要切记,在执行多任务时,并不是越多线程越好。
九、Json
Json简单说就是javascript中的对象和数组,所以这两种结构就是对象和数组两种结构,通过这两种结构可以表示各种复杂的结构
1.对象:对象在js中表示为{ }括起来的内容,数据结构为 { key:value, key:value, ... }的键值对的结构,在面向对象的语言中,key为对象的属性,value为对应的属性值,所以很容易理解,取值方法为 对象.key 获取属性值,这个属性值的类型可以是数字、字符串、数组、对象这几种。
2.数组:数组在js中是中括号[ ]括起来的内容,数据结构为 ["Python", "javascript", "C++", ...],取值方式和所有语言中一样,使用索引获取,字段值的类型可以是 数字、字符串、数组、对象几种
1. json.loads()
把Json格式字符串解码转换成Python对象 从json到python的类型转化对照如下:
Json
Python
object
dict
array
list
string
unicode
number(int)
float,long
true
True
false
False
null
None
# json_loads.py
import json
strList = '[1, 2, 3, 4]'
strDict = '{"city": "北京", "name": "大猫"}'
json.loads(strList)
# [1, 2, 3, 4]
json.loads(strDict) # json数据自动按Unicode存储
# {u'city': u'\u5317\u4eac', u'name': u'\u5927\u732b'}
- 2. json.dumps()
实现python类型转化为json字符串,返回一个str对象 把一个Python对象编码转换成Json字符串
Python
JSON
dict
object
list,tuple
array
str,unicode
string
int,long,float
number
True
true
Flase
Flase
None
null
# json_dumps.py
import json
import chardet
listStr = [1, 2, 3, 4]
tupleStr = (1, 2, 3, 4)
dictStr = {"city": "北京", "name": "大猫"}
json.dumps(listStr)
# '[1, 2, 3, 4]'
json.dumps(tupleStr)
# '[1, 2, 3, 4]'
# 注意:json.dumps() 序列化时默认使用的ascii编码
# 添加参数 ensure_ascii=False 禁用ascii编码,按utf-8编码
json_str = json.dumps(dictStr, ensure_ascii=False)
print(json_str)
# {"city": "北京", "name": "大刘"}
#使用这个模块可以检查编码的类型
chardet.detect(json.dumps(dictStr, ensure_ascii=False))
# {'confidence': 0.99, 'encoding': 'utf-8'}
- 3. json.dump()
将Python内置类型序列化为json对象后写入文件
# json_dump.py
import json
listStr = [{"city": "北京"}, {"name": "大刘"}]
json.dump(
listStr,
open("listStr.json","w"),
ensure_ascii=False
)
dictStr = {"city": "北京", "name": "大刘"}
json.dump(
dictStr,
open("dictStr.json","w"), ensure_ascii=False
)
- 4.json.load()
读取文件中json形式的字符串元素 转化成python类型
# json_load.py
import json
strList = json.load(open("listStr.json"))
print strList
# [{u'city': u'\u5317\u4eac'}, {u'name': u'\u5927\u5218'}]
strDict = json.load(open("dictStr.json"))
print strDict
# {u'city': u'\u5317\u4eac', u'name': u'\u5927\u5218'}