标签进行定义。如果不定义边框属性,表格将不显示边框。有时这很有用,但是大多数时候,我们希望显示边框。使用边框属性来显示一个带有边框的表格: Header 1 | Header 2 | row 1, cell 1 | row 1, cell 2 | row 2, cell 1 | row 2, cell 2 |
3> 列表速查 A: 基本文档 文档可见文本...
B: 基本标签 h1-h6 块元素 独立成行 行间距 属性: align 对齐方式 left center right color 不存在 如果需要设置样式 要嵌套font标签 . . . . . . . . . . . . 这是一个段落。 (换行) (水平线)
C: 文本格式化 粗体文本计算机代码 强调文本斜体文本键盘输入 预格式化文本 更小的文本重要的文本 (缩写) (联系信息) (文字方向) (从另一个源引用的部分) (工作的名称) (删除的文本) (插入的文本) (下标文本) (上标文本)
D: 链接 普通的链接:链接文本图像链接: 邮件链接: 发送e-mail书签:提示部分跳到提示部分
E: 图片
F: 样式/区块 文档中的块级元素 文档中的内联元素
G: 列表 无序列表
有序列表 - 第一项
- 第二项
H: 定义列表 - 项目 1
- 描述项目 1
- 项目 2
- 描述项目 2
I: 表格
J: 框架
K: 实体 < 等同于 <> 等同于 >© 等同于 ©
M: 文本修饰 font 行内标签 属性: size 字体大小 最大值是7 color 颜色值 颜色单词 red green blue 颜色的RGB rgb(0,0,255) 十六进制表示 #0000ff face 字体族 黑体 楷体 宋体 华文彩云 必须浏览器支持 Title 主题内容。 我还是主体内容
5> HTML语法基本规则 序列 | 规则内容 |
---|
1 | 根标签有且只能有一个 | 2 | 标签可以嵌套但不能交叉嵌套 | 3 | 注释不能嵌套 | 4 | 属性必须有值,值必须加引号,单引号或双引号均可 | 5 | 标签名不区分大小写但建议使用小写 | 6> Htlm特点 序列 | 内容 |
---|
1 | 使用是一对一对的标签组成;双标签 可以嵌套其他标签 | 2 | 标签之间可以相互嵌套,但是不可以交叉嵌套;;; | 3 | 使用属性去区分标签不同; ; | 1. BeautifulSoup 在使用BeautiSoup对其进行解析,解析的时候要使用相应类型的解析器html.parser from bs4 import BeautifulSoupfile = open(r'C:/Users/CHH_PC/Desktop/test.html','rb')html = file.read()bs = BeautifulSoup(html,'html.parser')
BeautifulSoup 将复杂的HTML文档转换成一个复杂的树形结构,每个结点都是一个Python对象,所有对象可以分为四种: 对象 | 含义 |
---|
Tag | 标签及其内容:拿到它所找到的第一个内容; | NavigableString | 这个内容就是NavigableString(标签里的内容,string) | BeautifulSoup | 表示对整个文档的访问 | Comment | 是一个特殊的NavigableString,输出内容不包括注释符号 | 2. BeautifulSoup应用 1> 常用参数 用法 | 解释 |
---|
bs.title | Tag 标签及其内容:拿到它所找到的第一个内容 | bs.title.string | 只获得标签的内容,不要标签 | bs.a.attrs | 快速拿到标签里面的所有属性 | bs.NavigableString | NavigableString用.string获取标签内部的文字。 | bs…head | 获取head标签的所有内容 | bs.head.contents | head文档的遍历 | bs.body.contents | body文档的遍历 | bs.body.contents[1] | body中第一个文档的遍历;content可遍历的内容有很多,获取Tag所有的子节点,返回一个list;contents[1] 用列表索引获取它的某一个元素 | bs…prettify() | 获取HTML的缩进格式 | bs…title | 获取title标签的所有内容 | bs.title.name | 获取title标签的名称 | bs.title.string | 获取title的文本内容 | bs.div | 获取第一个div标签中的所有内容 | bs.div[‘id’] | 获取第一个div标签的id的值 | bs.a | 获取第一个a标签中的所有内容 | bs.find_all(‘a’) | 获取所有的a标签中的所有内容 | 2> 遍历文档树 其他参数 | demo |
---|
children | for child in bs.body.contents[9].children: print(child);hildren 获取 Tag 所有的子节点,返回一个 生成器 | .descsndants | 获取 Tag 所有的子孙节点 | .strings | 如果Tag包含多个字符串,即在子孙节点中,可以用此获取,再进行遍历; | .striped_strings | 与strings 用法一致,清除多余的空白字符串;for child in bs.body.contents[9].stripped_strings: print(child) | .parent | 获取Tag 父节点 | .parents | 递归得到父辈元素的所有节点,返回一个生成器; | .previous_sibling | 获取当前Tag上一个节点,属性通常是字符串或者空白,真实结果其实是当前标签与上一个标签之间的顿号与换行符; | .next_sibling | 获取当前Tag下一个节点,属性通常是字符串或者空白,真实结果其实是当前标签与下一个标签之间的顿号与换行符; | .previous_siblings | 获取当前Tag上面所有的兄弟节点,返回一个生成器; | .next_siblings | 获取当前Tag下面所有的兄弟节点,返回一个生成器; | .previous_element | 获取解析过程中上一个被解析的对象,可能与previous_sibling相同,但通常都不同, | .next_element | 获取解析过程中下一个被解析的对象,可能与previous_sibling相同,但通常都不同; | .previous_elements | 返回一个生成器,可以向前访问文档的解析内容; | .next_elements | 返回一个生成器,可以向后访问文档的解析内容; | 3> 文档的搜索 参数 | 含义 |
---|
find_all() | divs_bs = bs.find_all(‘div’) print(divs_bs)找到所有的列标签,统一放到divs_bs ;也可以编译一个find_all(re.compile(‘a’))对象,然后find_all其中的内容 | kwargs(参数) | divs_bs = bs.find_all( id=“wp”)或者 divs_bs = bs.find_all(‘div’, id=“wp”) 再进行遍历 | text | divs_bs = bs.find_all( text=“请输入搜索内容”);其他属性divs_bs = bs.find_all( value=“请输入搜索内容”) | limit | divs_bs = bs.find_all(‘div’, limit=1) print(divs_bs);输出一个div信息 | css选择器 | 含义 |
---|
titlehead\body | divs_bs = bs.select(‘title’) 通过title查询; | # | divs_bs = bs.select(“#toptb”) 加# 通过ID查找 | . | divs_bs = bs.select(“.pg_index”) 加 . 通过类名查找 | head > title | divs_bs = bs.select(‘head > title’) 通过子标签查询; | a | ivs_bs = bs.select(“a[class=‘sister’]”) 按照属性查找 | 4> BeautifulSoup解析器 解析器 | 语法 | 优势 | 劣势 |
---|
Python标准库 | BeautifulSoup(html, ‘html.parser’) | Python的内置标准、执行速度适中、文档容错能力强 | Python2.7.3及Python3.2.2之前的版本文档容错能力差 | lxml HTML解析库 | BeautifulSoup(html, ‘lxml’) | 速度快、文档容错能力强 | 需要安装C语言库 | lxml XML解析库 | BeautifulSoup(html, ‘xml’) | 速度快、唯一支持XML的解析器 | 速度快、唯一支持XML的解析器 | html5lib解析库 | BeautifulSoup(html, ‘html5lib’) | 最好的容错性、以浏览器的方式解析文档,生成HTMLS格式的文档 | 速度慢、不依赖外部扩展 | 例如: soup = BeautifulSoup(html, ‘lxml’)创建对象 soup = BeautifulSoup(open(‘test.html’),‘lxml’)读取HTML文件 5> BeautifulSoup 高阶 A: find_all 参数举例 举例 | 含义 |
---|
soup.find_all(‘a’) | 查找与字符串完整匹配的内容,用于查找文档中所有的标签 | soup.find_all(re.compile(‘^b’)) | 传入正则表达式,BeautifulSoup会通过正则表达式的match()来匹配内容。返回所有表示和标签。 | soup.find_all([‘p’,‘a’]) | 传入列表参数,BeautifulSoup会与列表中任一元素匹配的内容返回。返回所有的 和标签 | soup.find_all(text=re.compile(‘^b’)) | 匹配正则表达式 | soup.find_all(传方法) | soup.find_all(test_def);def test_def: return tag.has_attr(“class”) 此处传参方法,判断标签是否含有class信息 | 1. urllib库的作用-解析网页 作用:urllib 模块是一个高级的 web 交流库,其核心功能就是模仿web浏览器等客户端,去请求相应的资源,并返回一个类文件对象。可以使用代码模拟浏览器发起请求 urllib 是python3 的内置库,urllib库最大的作用就是可以去设定相关的头部信息然后和网站建立请求连接,请求连接建立完成后就能够去获取到网页的整体数据,这也是python爬虫脚本实现的核心 2. urllib子模块 urllib模块包括:urllib.request, urllib.error, urllib.parse,urllib.robotparser 子模块 | 解释 |
---|
urllib.request | 请求模块-可以用来发送request和获取request的结果 | urllib.error | 异常处理模块-包含了urllib.request产生的异常 | urllib.parse | url解析模块-用来解析和处理https://blog.csdn.net/weixin_42914706/article/details/URL | urllib.robotparser | robots.txt解析模块-用来解析页面的robots.txt文件 | 模拟请求使用的最主要的库便是urllib.request,异常处理用urllib.error库 3. 使用流程 序列 | 步骤 |
---|
1 | 指定url | 2 | 发起请求:针对指定的url发起一个请求 | 3 | 获取页面数据:获取服务器响应回来的页面数据 | 4 | 持久化存储 | 4. urllib.request 发送请求 urllib.request 模块提供了最基本的构造 HTTP 请求的方法,利用它可以模拟浏览器的一个请求发起过程,同时它还带有处理 authenticaton (授权验证), redirections (重定向), cookies (浏览器Cookies)以及其它内容 demo 1> demo import urllib.requestresponse = urllib.request.urlopen("https://www.baidu.com")print(response)====================返回一个一个 HTTPResposne 类型的对象,它包含方法有 read() 、 readinto() 、getheader(name) 、 getheaders() 、 fileno() 等函数和 msg 、 version 、 status 、 reason 、 debuglevel 、 closed 等属性,所以可以通过response 调用这些方法和属性
2> 函数 函数 | 含义 |
---|
response.status | 返回结果的状态码,如200代表请求成功,404代表网页未找到等 | response.getheaders() | 返回list 格式head 信息 | response.getheader(“Server”) | 查询具体信息 | response.read() | 读取返回信息 | 5. urllib.request.urlopen() def urlopen(url, data=None, timeout=socket._GLOBAL_DEFAULT_TIMEOUT, *, cafile=None, capath=None, cadefault=False, context=None)
属性 | 理解 |
---|
data | 参数是可选的;如果要添加 data ,它要是字节流编码格式的内容,即 bytes 类型,通过 bytes() 函数可以进行转化,另外如果你传递了这个 data 参数,它的请求方式就不再是 GET 方式请求,而是 POST | timeout | timeout 参数可以设置超时时间,单位为秒,意思就是如果请求超出了设置的这个时间还没有得到响应,就会抛出异常,如果不指定,就会使用全局默认时间。它支持 HTTP 、 HTTPS 、 FTP 请求 | cafile 和 capath | 两个参数是指定CA证书和它的路径,这个在请求 HTTPS 链接时会有用 | cadefault | 参数现在已经弃用了,默认为 False | 1> data import urllib.parseimport urllib.requestdata = bytes(urllib.parse.urlencode({'word': 'hello'}), encoding='utf8')response = urllib.request.urlopen('http://httpbin.org/post', data=data)print(response.read().decode()) # 把bety转换为字典形式数据========================{ "args": {}, "data": "", "files": {}, "form": { "word": "hello" }, "headers": { "Accept-Encoding": "identity", "Content-Length": "10", "Content-Type": "application/x-www-form-urlencoded", "Host": "httpbin.org", "User-Agent": "Python-urllib/3.7", "X-Amzn-Trace-Id": "Root=1-63f61236-4616d33d219931e3332ba8b5" }, "json": null, "origin": "117.143.152.208", "url": "http://httpbin.org/post"}
POST 请求: 这里我们传递了一个参数 word ,值是 hello 。它需要被转码成 bytes (字节流)类型。其中转字节流采用了 bytes() 方法; 第一个参数需要是 str (字符串)类型,需要用 urllib.parse.urlencode() 方法来将参数字典转化为字符串。 第二个参数指定编码格式,在这里指定为 utf8 2> timeout import urllib.requestresponse = urllib.request.urlopen("https://www.baidu.com/?tn=65081411_1_oem_dg",timeout=1)print(response.read().decode())
设置了超时时间是1秒,程序1秒过后服务器依然没有响应,于是抛出了 urllib.error.https://blog.csdn.net/weixin_42914706/article/details/URLError: 异常,错误原因是 timed out;因此我们可以通过设置这个超时时间来控制一个网页如果长时间未响应就跳过它的抓取,利用 try,except 语句就可以实现这样的操作 import urllib.requestimport socketimport urllib.errortry: response = urllib.request.urlopen('http://httpbin.org/get',timeout=0.1)except urllib.error.https://blog.csdn.net/weixin_42914706/article/details/URLError as e: if isinstance(e.reason, socket.timeout): print("Time out!")
3> Request 1. Request 详解 import urllib.requestrequest = urllib.request.Request("https://www.baidu.com")response = urllib.request.urlopen(request)print(response.read().decode("utf-8"))
依然是用 urlopen() 方法来发送这个请求,只不过这次 urlopen() 方法的参数不再是一个https://blog.csdn.net/weixin_42914706/article/details/URL,而是一个 Request ,通过构造这个这个数据结构,一方面我们可以将请求独立成一个对象,另一方面可配置参数更加 丰富和灵活 def __init__(self, url, data=None, headers={}, origin_req_host=None, unverifiable=False, method=None):
参数 | 含义 |
---|
url | 参数是请求链接,这个是必传参数,其他的都是可选参数 | data | 参数如果要传必须传 bytes (字节流)类型的,如果是一个字典,可以先用 urllib.parse.urlencode() 编码。 | headers | 参数是一个字典,你可以在构造 Request 时通过 headers 参数传递,也可以通过调用 Request 对象的 add_header() 方法来添加请求头。请求头最常用的用法就是通过修改 User-Agent 来伪装浏览器,默认的 User-Agent 是 Python-urllib ,你可以通过修改它来伪装浏览器,比如要伪装火狐浏览器,你可以把它设置为 Mozilla/5.0 (X11; U; Linux i686)Gecko/20071127 Firefox/2.0.0.11 | origin_req_host | 指的是请求方的 host 名称或者 IP 地址 | unverifiable | 指的是这个请求是否是无法验证的,默认是 False 。意思就是说用户没有足够权限来选择接收这个请求的结果。例如我们请求一个HTML文档中的图片,但是我们没有自动抓取图像的权限,这时 unverifiable 的值就是 True | method | 是一个字符串,它用来指示请求使用的方法,比如 GET , POST , PUT 等等 | 2. 传入多个参数构建一个 Request 通过四个参数构造了一个 Request , url 即请求链接,在 headers 中指定了 User-Agent 和 Host ,传递的参数 data 用了 urlencode() 和 bytes() 方法来转成字节流,另外指定了请求方式为 POST from urllib import request,parseurl = "http://httpbin.org/post"headers = { #伪装一个火狐浏览器 "User-Agent":'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)', "host":'httpbin.org'}dict = { "name":"Germey"}data = bytes(parse.urlencode(dict),encoding="utf8")req = request.Request(url=url,data=data,headers=headers,method="POST")response = request.urlopen(req)print(response.read().decode("utf-8"))=========================={ "args": {}, "data": "", "files": {}, "form": { "name": "Germey" }, "headers": { "Accept-Encoding": "identity", "Content-Length": "11", "Content-Type": "application/x-www-form-urlencoded", "Host": "httpbin.org", "User-Agent": "Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)", "X-Amzn-Trace-Id": "Root=1-63f61795-1ff741e6101a79d9442e056c" }, "json": null, "origin": "117.143.152.208", "url": "http://httpbin.org/post"}Process finished with exit code 0
headers 也可以用 add_header() 方法来添加。 req = request.Request(url=url, data=data, method=‘POST’) req.add_header(‘User-Agent’, ‘Mozilla/4.0 (compatible; MSIE 5.5;Windows NT)’) 如此一来,我们就可以更加方便地构造一个 Request ,实现请求的发送 6. urllib.request高级特性 虽然可以构造 Request ,但是一些更高级的操作,比如 Cookies 处理,代理该怎样来设置?需要更强大的工具 Handler ; 简而言之你可以把它理解为各种处理器,有专门处理登录验证的,有处理 Cookies 的,有处理代理设置的,利用它们我们几乎可以做到任何 HTTP 请求中所有的事情 1> urllib.request.BaseHandler 它是所有其他 Handler 的父类,它提供了最基本的 Handler 的方法,例 如 default_open() 、 protocol_request() 等 BaseHandler 子类 | 含义 |
---|
HTTPDefaultErrorHandler | 用于处理HTTP响应错误,错误都会抛出 HTTPError 类型的异常 | HTTPRedirectHandler | 用于处理重定向 | HTTPCookieProcessor | 用于处理 Cookie | ProxyHandler | 用于设置代理,默认代理为空 | HTTPPasswordMgr | 用于管理密码,它维护了用户名密码的表 | HTTPBasicAuthHandler | 用于管理认证,如果一个链接打开时需要认证,那么可以用它来解决认证问题 | 实例代码1 import urllib.requestauth_handler = urllib.request.HTTPBasicAuthHandler()auth_handler.add_password(realm='PDQ Application', uri='https://mahler:8092/site-updates.py', user='klem', passwd='kadidd!ehopper')opener = urllib.request.build_opener(auth_handler)urllib.request.install_opener(opener)urllib.request.urlopen('http://www.example.com/login.html'=============================说明 Handler 和 Opener 的使用方法。在这里,首先实例化了一个 HTTPBasicAuthHandler 对象,利用 add_password() 添加进去用户名和密码,相当于建立了一个处理认证的处理器;接下来利用 urllib.request.build_opener() 方法来利用这个处理器构建一个 Opener ,那么这个 Opener 在发送请求的时候就具备了认证功能了。接下来利用 Opener 的 open() 方法打开链接,就可以完成认证了
实例代码2 代理 import urllib.requestproxy_handler = urllib.request.ProxyHandler({'http': 'http://218.202.111.10:80','https': 'https://180.250.163.34:8888'})opener = urllib.request.build_opener(proxy_handler)response = opener.open('https://www.baidu.com')print(response.read())=============================用于说明代理的设置方法,代理可能已经失效。在这里使用了 ProxyHandler , ProxyHandler 的参数是一个字典,key是协议类型,比如 http 还是 https 等,value是代理链接,可以添加多个代理。然后利用 build_opener() 方法利用这个 Handler 构造一个 Opener ,然后发送请求即可
2> Cookie设置 获取网站的 Cookie import http.cookiejar, urllib.requestcookie = http.cookiejar.CookieJar() 或则cookie = http.cookiejar.LWPCookieJar(filename)# LWPCookieJar ,同样可以读取和保存 Cookie ,但是保存的格式和 MozillaCookieJar 的不一样,它会保存成与libwww-perl的Set-Cookie3文件格式的 Cookiehandler = urllib.request.HTTPCookieProcessor(cookie)opener = urllib.request.build_opener(handler)response = opener.open('http://www.baidu.com')for item in cookie: print(item.name+"="+item.value)========================打印BAIDUID=8D12919D30F39DFDD8FC36AC5F965BD4:FG=1BIDUPSID=8D12919D30F39DFDD1ED7D576F0628B2H_PS_PSSID=36561_38129_37906_37861_38264_38173_38289_38243_38034_38263_37928_38285_26350_22157_37881PSTM=1678009542BDSVRTM=0BD_HOME=1===============================================首先必须声明一个 CookieJar 对象,接下来我们就需要利用 HTTPCookieProcessor 来构建一个 handler ,最后利用 build_opener 方法构建出 opener ,执行 open() 即可
Cookie 实际也是以文本形式保存 filename = 'cookie.txt'cookie = http.cookiejar.MozillaCookieJar(filename)handler = urllib.request.HTTPCookieProcessor(cookie)opener = urllib.request.build_opener(handler)response = opener.open('http://www.baidu.com')cookie.save(ignore_discard=True, ignore_expires=True)===================这时的 CookieJar 就需要换成 MozillaCookieJar ,生成文件时需要用到它,它是 CookieJar 的子类,可以用来处理 Cookie 和文件相关的事件,读取和保存 Cookie ,它可以将 Cookie 保存成 Mozilla 型的格式;运行之后可以发现生成了一个 cookie.txt 文件
从文件读取并利用Cookie 信息 cookie = http.cookiejar.LWPCookieJar()cookie.load('cookie.txt', ignore_discard=True, ignore_expires=True)handler = urllib.request.HTTPCookieProcessor(cookie)opener = urllib.request.build_opener(handler)response = opener.open('http://www.baidu.com')print(response.read().decode('utf-8'))===========================利用上面的方式生成了 LWPCookieJar 格式的 Cookie ,然后利用 load() 方法,传入文件名称,后面同样的方法构建 handler 和 opener 即可
python 数据分析之 xlsxwriter文件解析 https://blog.csdn.net/weixin_42914706/article/details/129116587 来源地址:https://blog.csdn.net/weixin_42914706/article/details/129112667 免责声明: ① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。 ② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341 python 数据分析之 HTML文件解析下载Word文档到电脑,方便收藏和打印~ 下载Word文档 猜你喜欢 python数据分析之pandas数据选Pandas是作为Python数据分析著名的工具包,提供了多种数据选取的方法,方便实用。本文主要介绍Pandas的几种数据选取的方法。 Pandas中,数据主要保存为Dataframe和Series是数据结构,这两种数据结构数据选取的方式 2023-01-30 Python数据分析之pandas读取数据一、三种数据文件的读取二、csv、tsv、txt 文件读取
1)CSV文件读取:
语法格式:pandas.read_csv(文件路径)
CSV文件内容如下:import pandas as pd
file_path = "e:\\panda 2022-06-02 Python数据分析库之pandas,你写这个系列背后的故事咦,面试系列的把基础部分都写完啦,哈哈答,接下来要弄啥嘞~pandas吧外国人开发的翻译成汉语叫 熊猫厉害厉害,很接地气一个基于numpy的库干啥的?做数据分析用的而数据分析是python体系下一个非常庞大的分支厉害到, 2023-01-31 Python的xpath数据解析案例分析这篇“Python的xpath数据解析案例分析”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Python的xpath数据解析 2023-06-29 数据分析之matplotlib.pypl首先都得导模块。import numpy as npimport pandas as pdimport matplotlib.pyplot as pltfrom pandas import Series,DataFrame 一、绘制单线图 2023-01-30 编程热搜 一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】- chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列 可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃 Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python 一、前言 在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install 和 pip , 目前官方推荐使用 pip。
|