爬虫基础
爬虫认知
是一种按照一定的规则,自动地抓取万维网信息的程序或者脚本。通俗的讲: 就是模拟客户端发起网络请求,接收请求的响应,按照一定的规则,自动的抓取互联网信息的程序。
网络请求
urllib库
导入库
from urllib import request
from urllib import parse
urlopen()函数
"""
urlopen()函数:在urllib.request模块中,用来网络请求
参数: 1.url:请求网站的url 2.data:请求的data提交的表单数据
返回值: 返回值是一个 http.client.HTTPResponse 对象,这个对象是一个类文件句柄对象。
有 read(size) 、 readline 、 readlines 以及 getcode 等方法。
"""
# respone = request.urlopen('http://www.baidu.com')
# print(respone.getcode())
urlretrieve() 函数
"""
urlretrieve() 函数的用法: 将网页上的文件保存到本地
参数:1.文件地址 2.要保存的文件名 + 后缀名
"""
# img_url = 'https://edu-image.nosdn.127.net/deaf24ba-2bd5-4266-8c65-a9a615fef61e.jpg?imageView&quality=100&crop=0_0_1080_680&thumbnail=450y250'
# request.urlretrieve(img_url,'21天搞定Python分布爬虫.png')
urlencode()函数
"""
urlencode()函数用法: 发送请求时候,如果url中包含中文或者其他特殊字符,则需要进行路径编码
urlencode 可以把字典塑胶转换成URL编码的数据
"""
# params = {'name':'张三',"age":18,'greet':'hello world'}
# result = parse.urlencode(params)
# print(result)
# url = 'http://www.baidu.com/s'
# params = {"wd":"刘德华"}
# qs = parse.urlencode(params)
# url = url + "?" + qs
# resp = request.urlopen(url)
# print(resp.read())
parse_qs()函数
"""
parse_qs()函数用法: 讲经过编码后的url参数进行解码
"""
# params = {'name':'张三',"age":18,'greet':'hello world'}
# qs = parse.urlencode(params) # 编码
# print(qs)
# restult = parse.parse_qs(qs) # 解码
# print(restult)
#
urlparse() 和 urlsplit()函数
"""
urlparse() 和 urlsplit()函数: 将URL中各个组成部分进行分割
区别: urlparse 里面多了一个 params 属性,而 urlsplit 没有这个 params 属性。
"""
# url = 'http://www.baidu.com/s?username=zhiliao'
#
# result = parse.urlsplit(url)
# result2 = parse.urlparse(url)
#
# print('urlsplit: ',result)
# print('urlparse: ',result2)
#
# print('scheme: ',result.scheme)
# print('netloc ',result.netloc)
# print('path ',result.path)
# print('query ',result.query)
request.Request类
"""
request.Request类:
# 如果要在请求时候添加某些 请求信息(如:headers、data等 网络请求必须要的参数),就需要 Request类进行封装请求数据
# 类型转换: str => bytes:encode() ; bytes => str:decode()
# Request:默认情况是 get()请求方法,但是只要传了 data参数,就是post()请求方法
"""
# from urllib import request,parse
#
# url = "https://music.163.com/weapi/cloudsearch/get/web?csrf_token="
# headers = {
# "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36"
# }
# formdata = {
# "params": "foUlX36kSAGPWtUp5SoqQTK9qDpJUuld45H57CYE49VM4zPJq8qwZxFwvL5djdWf61EFKPmFBZEzQ0wajuz1dE8a/pPKLciXET2mpGG3Pq1cWCMkOL1/kOSre2Qu0dHojZjHbHii/RbSNtmdIwVKbRD660wt8FBRRamrKbryU9NriJv5bLagmaFQ7aaOh5QQ6fjS2ENsAViwTVU58yvD85TWjS6zop28bhbLGePML4x3n8qaYIlAza4UNKaTAJ3wZNn7AdVP2FGbzD8NiSYjW/Wc+UwgsqWjsUU5wzmFf/Q=",
# "encSecKey": "32c74c08ae72ff1e5c39de0fb64b15b981d50f873a0afb73c4511939d67bc83fd101ed53f347798a10a86fb46cb55f651c1256413de44cd9ecc197c5cbd3eda58aa4075aeb2ca73b0fe4c6b23248200dc85b23f3206ab06e6e4568aa02219396b8203f886dc3fa08c2a7e2ff283eabf60e992bc10f7bafb9ab89ab8dd3b3a020"
# }
#
# req = request.Request(url=url,headers=headers,data=parse.urlencode(formdata).encode('utf-8'))
# resp = request.urlopen(req)
# print(resp.read().decode('utf-8'))
# from urllib import request
#
# headers = {
# "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.110 Safari/537.36",
# "Referer": "https://www.qiushibaike.com/text/",
# "Origin": "https://www.qiushibaike.com"
# }
# req = request.Request("https://www.qiushibaike.com/text/page/2/",headers=headers)
# resp = request.urlopen(req)
# print(resp.read().decode('utf-8'))
ProxyHandler()代理处理器
"""
ProxyHandler处理器(代理设置):
访问网站频繁被识别为 爬虫: 网站会检测某一段时间某个IP的访问次数,如果访问次数多的不像正常人,它会禁止这个IP的访问。
可以通过IP代理服务器 进行 反爬; 自定义 opener()方法 来使用代理
"""
# from urllib import request
#
# ## 没使用 IP代理情况
# # url = 'http://httpbin.org/ip'
# # resp = request.urlopen(url)
# # print(resp.read())
# ## 使用IP代理
# url = 'http://httpbin.org/ip'
# # 1. 使用ProxyHandler()方法,传入代理传教一个 handler
# handler = request.ProxyHandler({"118.113.245.100":"9999"}) # ProxyHandler()传入一个字典:{"ip":"prot"}
# # 2.使用上面创建的handler 构建一个 opener 代理对象
# opener = request.build_opener(handler)
# # 3.使用 opener代理对象 发送请求
# resp = opener.open(url)
# print(resp.read())
ProxyHandler处理器 总结
"""
### ProxyHandler处理器(代理):
1. 代理的原理:在请求目的网站之前,先请求代理服务器,然后让代理服务器去请求目的网站,
代理服务器拿到目的网站的数据后,再转发给我们的代码。
2. http://httpbin.org:这个网站可以方便的查看http请求的一些参数。
3. 在代码中使用代理:
* 使用`urllib.request.ProxyHandler`,传入一个代理,这个代理是一个字典,
字典的key依赖于代理服务器能够接收的类型,一般是`http`或者`https`,值是`ip:port`。
* 使用上一步创建的`handler`,以及`request.build_opener`创建一个`opener`对象。
* 使用上一步创建的`opener`,调用`open`函数,发起请求。
示例代码如下:
```python
from urllib import request
url = 'http://httpbin.org/ip'
# 1. 使用ProxyHandler,传入代理构建一个handler
handler = request.ProxyHandler({"http":"223.241.78.43:8010"})
# 2. 使用上面创建的handler构建一个opener
opener = request.build_opener(handler)
# 3. 使用opener去发送一个请求
resp = opener.open(url)
print(resp.read())
```
"""
Cookie技术
"""
网络连接中,http协议是无状态的、没记忆:服务器与 客服端 无法进行识别;从而无法可持续进行数据传输、交互;
Cookie技术 :则是解决http传输协议的缺点,保存 服务器和客户端 连接后的认证信息,让两者后续 进行有效的 连接、访问、交流
"""
""" 保存 cookie 到本地,可以使用 cookiejar 的 save 方法,并且需要指定一个文件名: """
# from urllib import request
# from http.cookiejar import MozillaCookieJar
#
# headers = {
# 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML,like Gecko) Chrome/62.0.3202.94 Safari/537.36'
# }
#
# cookiejar = MozillaCookieJar("cookie.txt") # 生成 存储 cookie的文件
# handler = request.HTTPCookieProcessor(cookiejar)
# opener = request.build_opener(handler)
#
# req = request.Request('http://httpbin.org/cookies',headers=headers)
# resp = opener.open(req)
#
# print(resp.read())
# cookiejar.save(ignore_discard=True,ignore_expires=True) # 保存 cookie
"""从本地加载 cookie ,需要使用 cookiejar 的 load 方法,并且也需要指定方法:"""
# from urllib import request
# from http.cookiejar import MozillaCookieJar
#
# headers = {
# 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML,like Gecko) Chrome/62.0.3202.94 Safari/537.36'
# }
#
# cookiejar = MozillaCookieJar('cookie.txt')
# cookiejar.load(ignore_discard=True) # 加载 cookie文件 信息
# handler = request.HTTPCookieProcessor(cookiejar)
# opener = request.build_opener(handler)
#
# resp = opener.open('http://httpbin.org/cookies')
# for cookie in cookiejar:
# print(cookie)
# 大鹏董成鹏主页:http://www.renren.com/880151247/profile
# 人人网登录url:http://www.renren.com/PLogin.do
"""1. 不使用cookie去请求大鹏的主页 => 结果:请求失败,需要登录验证;"""
from urllib import request
# dapeng_url = "http://www.renren.com/880151247/profile"
# headers = {
# 'User-Agent':"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36",
# "Cookie":"anonymid=jacdwz2x-8bjldx; depovince=GW; _r01_=1; _ga=GA1.2.1455063316.1511436360; _gid=GA1.2.862627163.1511436360; wp=1; JSESSIONID=abcrs0queAwRp_sk9dS-v; ch_id=10016; jebecookies=c68b9b55-b6a1-4661-8d11-832862cfa246|||||; ick_login=7e3299f4-1e31-4455-b2a4-e5317c9e2ccf; _de=EA5778F44555C091303554EBBEB4676C696BF75400CE19CC; p=a96969b7912d80d95127b7935c1b729e1; first_login_flag=1; ln_uact=970138074@qq.com; ln_hurl=http://hdn.xnimg.cn/photos/hdn121/20170428/1700/main_nhiB_aebd0000854a1986.jpg; t=4d2ccb81ee83a6b1d3925b94779d22e21; societyguester=4d2ccb81ee83a6b1d3925b94779d22e21; id=443362311; xnsid=13bf03ea; loginfrom=syshome; jebe_key=9c062f5a-4335-4a91-bf7a-970f8b86a64e%7Ca022c303305d1b2ab6b5089643e4b5de%7C1511449232839%7C1; wp_fold=0"
# }
# req = request.Request(url=dapeng_url,headers=headers)
# resp = request.urlopen(req)
# with open('renren.html','w',encoding='utf-8') as fp:
# # write函数必须写入一个str的数据类型
# # resp.read()读出来的是一个bytes数据类型
# # bytes -> decode -> str
# # str -> encode -> bytes
# fp.write(resp.read().decode('utf-8'))
# 大鹏董成鹏主页:http://www.renren.com/880151247/profile
# 人人网登录url:http://www.renren.com/PLogin.do
"""2. 使用cookie去请求大鹏的主页 => 结果:请求成功,返回对应信息"""
from urllib import request
from urllib import parse
from http.cookiejar import CookieJar
headers = {
'User-Agent':"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36"
}
# 创建 共享的请求对象,保存验证信息
def get_opener():
cookiejar = CookieJar() # 创建 cookiejar 对象
handler = request.HTTPCookieProcessor(cookiejar) # 创建一个 HTTPCookieProcessor() HttpCookie处理器对象
opener = request.build_opener(handler) # 创建一个 携带cookie信息的 opener()请求对象
return opener
# 登录,并获取登录信息
def login_renren(opener):
# 1.使用opener发送登录的请求(人人网的邮箱和密码)
data = {
'email':"970138074@qq.com",
'password': "pythonspider"
}
login_url = "http://www.renren.com/PLogin.do"
req = request.Request(login_url,data=parse.urlencode(data).encode('utf-8'),headers=headers)
response = opener.open(req)
print(response.read().decode("utf-8"))
# 使用已登录信息,进行访问主页
def visit_profile(opener):
# 2. 访问个人主页
dapeng_url = "http://www.renren.com/880151247/profile"
# 获取个人主页的页面的时候,不要新建一个opener;而应该使用之前的那个opener,
# 因为之前的那个opener已经包含了登录所需要的cookie信息
req = request.Request(dapeng_url,headers=headers)
resp = opener.open(req)
with open('abc.html','w',encoding='utf-8') as fp:
fp.write(resp.read().decode('utf-8'))
if __name__ == '__main__':
opener = get_opener()
login_renren(opener)
visit_profile(opener)
requests库
requests库
"""
requests库:
虽然Python的标准库中 urllib模块已经包含了平常我们使用的大多数功能,但是它的 API 使用起来
让人感觉不太好,而 Requests宣传是 “HTTP for Humans”,说明使用更简洁方便。
"""
# import requests
#
# # 最简单的发送 get 请求就是通过 requests.get 来调用
# response = requests.get("https://www.baidu.com/") # params 接收一个字典或者字符串的查询参数,字典类型自动转换为url编码,不需要urlencode()
# print(type(response.text)) #
# print(response.text) #查看响应内容,response.text 返回的是Unicode格式的数据
# print(type(response.content)) #
# print(response.content) # 查看响应内容,response.content返回的字节流数据
# print(response.content.decode('utf-8')) #
#
# print(response.url) # # 查看完整url地址
# print(response.encoding) #查看响应头部字符编码
# print(response.status_code) # 查看响应码
发送GET请求
## 1. params 传入 参数形式:
# import requests
#
# params = {
# 'wd': '中国'
# }
# headers = {
# 'User-Agent': 'ozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36'
# }
# response = requests.get("https://www.baidu.com/s",params=params,headers=headers)
#
# with open('baidu.html','w',encoding='utf-8') as fp:
# fp.write(response.content.decode('utf-8'))
#
# print(response.url)
发送POST请求
## 2. data 传入 表单数据 形式:
# import requests
#
# url = 'https://www.lagou.com/jobs/positionAjax.json?city=%E6%B7%B1%E5%9C%B3&needAddtionalResult=false&isSchoolJob=0'
#
# data = {
# 'first':"true",
# 'pn': '1',
# 'kd': 'python'
# }
# headers = {
# 'Referer': 'https://www.lagou.com/jobs/list_python?labelWords=&fromSearch=true&suginput=',
# 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.84 Safari/537.36'
# }
#
# response = requests.post(url,data=data,headers=headers)
# print(type(response.json()))
# print(response.json())
proxies代理
## 3. proxies 传入 代理服务器 形式:
# import requests
#
# proxy = {
# 'http': '182.148.206.83:9999'
# }
#
# response = requests.get("http://httpbin.org/ip",proxies=proxy)
# print(response.text)
verify 处理不信任
## 4. verify 处理不信任的SSL证书 形式:
# import requests
#
# url = 'http://www.12306.cn/mormhweb/'
# resp = requests.get(url,verify=True)
# with open('12306.html','w',encoding='utf-8') as fp:
# fp.write(resp.text)
cookie
## 5. cookie:如果在一个响应中包含了 cookie ,返回的 cookie 值: 形式:
# import requests
# url = "http://www.renren.com/PLogin.do"
# data = {"email":"970138074@qq.com",'password':"pythonspider"}
# resp = requests.get('http://www.baidu.com/')
# print(resp.cookies)
# print(resp.cookies.get_dict())
session
## 6. session: 保存会话信息并 共享 cookie数据 形式:
import requests
# response = requests.get('https://www.baidu.com/')
# print(response.cookies.get_dict())
# url = "http://www.renren.com/PLogin.do"
# data = {"email":"970138074@qq.com",'password':"pythonspider"}
# headers = {
# 'User-Agent': "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36"
# }
#
# session = requests.Session()
#
# session.post(url,data=data,headers=headers) # 先提交数据,通过验证
#
# response = session.get('http://www.renren.com/880151247/profile') # 再访问主页
# with open('renren.html','w',encoding='utf-8') as fp:
# fp.write(response.text)
request 和 session 小案例
import requests
def renren():
url = "http://www.renren.com/PLogin.do"
data = {"email": "970138074@qq.com", 'password': "pythonspider"}
headers = {
'User-Agent': "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36"
}
# 登录
session = requests.session()
session.post(url, data=data, headers=headers)
# 访问大鹏个人中心
resp = session.get('http://www.renren.com/880151247/profile')
print(resp.text)
requests笔记
## 发送get请求:
发送get请求,直接调用`requests.get`就可以了。想要发送什么类型的请求,就调用什么方法。
```python
response = requests.get("https://www.baidu.com/")
```
## response的一些属性:
```python
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(response.content)
# 查看完整url地址
print(response.url)
# 查看响应头部字符编码
print(response.encoding)
# 查看响应码
print(response.status_code)
```
## response.text和response.content的区别:
1. response.content:这个是直接从网络上面抓取的数据。没有经过任何解码。所以是一个bytes类型。其实在硬盘上和在网络上传输的字符串都是bytes类型。
2. response.text:这个是str的数据类型,是requests库将response.content进行解码的字符串。解码需要指定一个编码方式,requests会根据自己的猜测来判断编码的方式。所以有时候可能会猜测错误,就会导致解码产生乱码。这时候就应该使用`response.content.decode('utf-8')`进行手动解码。
## 发送post请求:
发送post请求非常简单。直接调用`requests.post`方法就可以了。
如果返回的是json数据。那么可以调用`response.json()`来将json字符串转换为字典或者列表。
## 使用代理:
在请求方法中,传递`proxies`参数就可以了。
## 处理cookie:
如果想要在多次请求中共享cookie。那么应该使用session。示例代码如下:
```python
import requests
url = "http://www.renren.com/PLogin.do"
data = {"email":"970138074@qq.com",'password':"pythonspider"}
headers = {
'User-Agent': "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36"
}
session = requests.Session()
session.post(url,data=data,headers=headers)
response = session.get('http://www.renren.com/880151247/profile')
with open('renren.html','w',encoding='utf-8') as fp:
fp.write(response.text)
```
## 处理没有授权的https协议:
数据解析
xpath库
path语法
## 使用方式:
使用//获取整个页面当中的元素,然后写标签名,然后再写谓词进行提取。比如:
```
//div[@class='abc']
```
## 需要注意的知识点:
1. /和//的区别:/代表只获取直接子节点。//获取子孙节点。一般//用得比较多。当然也要视情况而定。
2. contains:有时候某个属性中包含了多个值,那么可以使用`contains`函数。示例代码如下:
```
//div[contains(@class,'job_detail')]
```
3. 谓词中的下标是从1开始的,不是从0开始的。
## 使用lxml解析HTML代码:
1. 解析html字符串:使用`lxml.etree.HTML`进行解析。示例代码如下:
```python
htmlElement = etree.HTML(text)
print(etree.tostring(htmlElement,encoding='utf-8').decode("utf-8"))
```
2. 解析html文件:使用`lxml.etree.parse`进行解析。示例代码如下:
```python
htmlElement = etree.parse("tencent.html")
print(etree.tostring(htmlElement, encoding='utf-8').decode('utf-8'))
```
这个函数默认使用的是`XML`解析器,所以如果碰到一些不规范的`HTML`代码的时候就会解析错误,这时候就要自己创建`HTML`解析器。
```python
parser = etree.HTMLParser(encoding='utf-8')
htmlElement = etree.parse("lagou.html",parser=parser)
print(etree.tostring(htmlElement, encoding='utf-8').decode('utf-8'))
```
## lxml结合xpath注意事项:
1. 使用`xpath`语法。应该使用`Element.xpath`方法。来执行xpath的选择。示例代码如下:
```python
trs = html.xpath("//tr[position()>1]")
```
`xpath函数`返回来的永远是一个列表。
2. 获取某个标签的属性:
```python
href = html.xpath("//a/@href")
# 获取a标签的href属性对应的值
```
3. 获取文本,是通过`xpath`中的`text()`函数。示例代码如下:
```python
address = tr.xpath("./td[4]/text()")[0]
```
4. 指定获取元素 下标范围,是通过`xpath`中的`position()`函数。示例代码如下:
```python
trs = html.xpath("//tr[position()>1]")
```
5. 在某个标签下,再执行xpath函数,获取这个标签下的子孙元素,那么应该在斜杠之前加一个点,代表是在当前元素下获取。示例代码如下:
```python
address = tr.xpath("./td[4]/text()")[0]
```
导入库
from lxml import etree
解析 HTML文件 和文本
class ParseFile():
def parse_text(self):
text = """html文本"""
# 调用 HTML()方法 来加载 html文本,并结构化
htmlElement = etree.HTML(text)
print(etree.tostring(htmlElement,encoding='utf8').decode('utf-8') )
def parse_tencent_file(self):
# 调用 XML模块中 etree类的parse方法,能导入文件并 解析
htmlElement = etree.parse("htmlElement.html")
print(etree.tostring(htmlElement, encoding='utf-8').decode('utf-8'))
def parse_lagou_file(self):
# 指定 HTMLParser解析器
# 调用 XML模块中 etree类的parse方法,能导入文件并 解析
parser = etree.HTMLParser(encoding='utf8')
htmlElement = etree.parse('lagou.html',parser=parser)
print(etree.tostring(htmlElement,encoding='utf-8').decode('utf-8'))
使用xpath 提取 元素
class ExtractElement(object):
parser = etree.HTMLParser(encoding='utf8')
htmlElement = etree.parse("tencent.html", parser=parser)
# 1. 获取所有tr标签
# trs = htmlElement.xpath('//tr')
# for tr in trs:
# print(etree.tostring(tr,encoding='utf8').decode('utf-8'))
# 2. 获取第2个tr标签
# tr = htmlElement.xpath('//tr[2]')[0]
# print(etree.tostring(tr,encoding='utf-8').decode('utf-8'))
# 3. 获取所有class等于even的tr标签
# trs = htmlElement.xpath("//tr[@class='even']")
# for tr in trs:
# print(etree.tostring(tr,encoding='utf-8').decode('utf-8'))
# 4. 获取所有a标签的href属性
# aList = htmlElement.xpath("//a/@href")
# for a in aList:
# print("http://hr.tencent.com/"+a)
# 5. 获取所有的职位信息(纯文本)
trs = htmlElement.xpath("//tr[position()>1]") # position()方法 获取 下标 大于 1 的 所有tr标签
positions = []
for tr in trs:
# 在某个标签下,再执行xpath函数,获取这个标签下的子孙元素
# 那么应该在//之前加一个点,代表是在当前元素下获取
href = tr.xpath(".//a/@href")[0]
fullurl = 'http://hr.tencent.com/' + href
title = tr.xpath("./td[1]//text()")[0]
category = tr.xpath("./td[2]/text()")[0]
nums = tr.xpath("./td[3]/text()")[0]
address = tr.xpath("./td[4]/text()")[0]
pubtime = tr.xpath("./td[5]/text()")[0]
position = {
'url': fullurl,
'title': title,
'category': category,
'nums': nums,
'address': address,
'pubtime': pubtime
}
positions.append(position)
print(positions)
ExtractElement()
beautifulsoup库
BeautifulSoup语法
## find_all的使用:
1. 在提取标签的时候,第一个参数是标签的名字。然后如果在提取标签的时候想要使用标签属性进行过滤,
那么可以在这个方法中通过关键字参数的形式,将属性的名字以及对应的值传进去。或者是使用`attrs`属性,
将所有的属性以及对应的值放在一个字典中传给`attrs`属性。
2. 有些时候,在提取标签的时候,不想提取那么多,那么可以使用`limit`参数。限制提取多少个。
## find与find_all的区别:
1. find:找到第一个满足条件的标签就返回。说白了,就是只会返回一个元素。
2. find_all:将所有满足条件的标签都返回。说白了,会返回很多标签(以列表的形式)。
## 使用find和find_all的过滤条件:
1. 关键字参数:将属性的名字作为关键字参数的名字,以及属性的值作为关键字参数的值进行过滤。
2. attrs参数:将属性条件放到一个字典中,传给attrs参数。
## 获取标签的属性:
1. 通过下标获取:通过标签的下标的方式。
```python
href = a['href']
```
2. 通过attrs属性获取:示例代码:
```python
href = a.attrs['href']
```
## string和strings、stripped_strings属性以及get_text方法:
1. string:获取某个标签下的非标签字符串。返回来的是个字符串。如果这个标签下有多行字符,那么就不能获取到了。
2. strings:获取某个标签下的子孙非标签字符串。返回来的是个生成器。
2. stripped_strings:获取某个标签下的子孙非标签字符串,会去掉空白字符。返回来的是个生成器。
4. get_text:获取某个标签下的子孙非标签字符串。不是以列表的形式返回,是以普通字符串返回。
## CSS选择器:
1. 根据标签的名字选择,示例代码如下:
```css
p{
background-color: pink;
}
```
2. 根据类名选择,那么要在类的前面加一个点。示例代码如下:
```css
.line{
background-color: pink;
}
```
3. 根据id名字选择,那么要在id的前面加一个#号。示例代码如下:
```css
#box{
background-color: pink;
}
```
4. 查找子孙元素。那么要在子孙元素中间有一个空格。示例代码如下:
```css
#box p{
background-color: pink;
}
```
5. 查找直接子元素。那么要在父子元素中间有一个>。示例代码如下:
```css
#box > p{
background-color: pink;
}
```
6. 根据属性的名字进行查找。那么应该先写标签名字,然后再在中括号中写属性的值。示例代码如下:
```css
input[name='username']{
background-color: pink;
}
```
7. 在根据类名或者id进行查找的时候,如果还要根据标签名进行过滤。那么可以在类的前面或者id的前面加上标签名字。示例代码如下:
```css
div#line{
background-color: pink;
}
div.line{
background-color: pink;
}
```
## BeautifulSop中使用css选择器:
在`BeautifulSoup`中,要使用css选择器,那么应该使用`soup.select()`方法。应该传递一个css选择器的字符串给select方法。
## 常见的四种对象:
1. Tag:BeautifulSoup中所有的标签都是Tag类型,并且BeautifulSoup的对象其实本质上也是一个Tag类型。所以其实一些方法比如find、find_all并不是BeautifulSoup的,而是Tag的。
2. NavigableString:继承自python中的str,用起来就跟使用python的str是一样的。
3. BeautifulSoup:继承自Tag。用来生成BeaufifulSoup树的。对于一些查找方法,比如find、select这些,其实还是Tag的。
4. Comment:这个也没什么好说,就是继承自NavigableString。
## contents和children:
返回某个标签下的直接子元素,其中也包括字符串。他们两的区别是:contents返回来的是一个列表,children返回的是一个迭代器。
"""
导入库
from bs4 import BeautifulSoup
bs4语法使用
from bs4 import BeautifulSoup
# html文本
html = """html文本"""
bs = BeautifulSoup(html,"lxml") # 创建一个bs4对象,传入 html数据,使用 lxml解析器来操作
## find_all()、string、stripped_strings 等方法 操作:
# 0. # 打印获取的数据
# print(bs.prettify())
# tr = bs.find_all('tr')[1]
# text = tr.string
# print(text)
# 1. 获取所有tr标签
# trs = bs.find_all('tr')
# for tr in trs:
# print(tr)
# print('*'*30)
# 2. 获取第2个tr标签
# tr = bs.find_all('tr',limit=2)[1]
# print(tr)
# 3. 获取所有class等于even的tr标签
# trs = bs.find_all('tr',attrs={'class':"even"})
# for tr in trs:
# print(tr)
# print('='*30)
# 4. 将所有id等于test,class也等于test的a标签提取出来。
# aList = bs.find_all('a',id='test',class_='test')
# aList2 = bs.find_all('a',attrs={'id':'test','class':'test'})
# for a in aList2:
# print(a)
# print('='*30)
# 5. 获取所有a标签的href属性 ==> 通过操作字典对象方式, 取key键名 来获取键值
# aList = bs.find_all('a')
# for a in aList:
# #1.通过下标操作方式
# href = a['href']
# print(href)
# print('*'*30)
#
# #2.通过attrs属性方式
# href = a.attrs['href']
# print(href)
# 6. 获取所有的职位信息(纯文本)
# trs = bs.find_all('tr')[1:] # 切片:除第一个外,获取所有tr元素
# movies = []
# for tr in trs:
# movie = {}
#
# ## 方式一: 通过 层级结构,获取一个个相对应 数据,再把数据组合添加到字典;最后把字典添加到列表;步骤繁多-操作复杂;
# # tds = tr.find_all("td")
# # title = tds[0].string
# # category = tds[1].string
# # nums = tds[2].string
# # city = tds[3].string
# # pubtime = tds[4].string
# # movie['title'] = title
# # movie['category'] = category
# # movie['nums'] = nums
# # movie['city'] = city
# # movie['pubtime'] = pubtime
# # movies.append(movie)
#
# ## 方式二: 去tags标签、制表符、空格 信息,获取 返回列表-文本数据 ;通过下标取值; 操作简单
# infos = list(tr.stripped_strings)
# print('infos:{}'.format(infos))
# movie['title'] = infos[0]
# movie['category'] = infos[1]
# movie['nums'] = infos[2]
# movie['city'] = infos[3]
# movie['pubtime'] = infos[4]
# movies.append(movie)
#
# print(movies)
CSS选择器
## CSS选择器: select()方法 操作
# 1. 获取所有tr标签
# trs = bs.select("tr")
# for tr in trs:
# print(type(tr))
# print('='*30)
# print(tr)
# break
# 2. 获取第2个tr标签
# tr = bs.select('tr')[1]
# print(tr)
# 3. 获取所有class等于even的tr标签
# # trs = bs.select(".even")
# trs2 = bs.select("tr[class='even']")
# for tr in trs2:
# print(tr)
# 4. 获取所有a标签的href属性
# aList = bs.select('a')
# for a in aList:
# href = a['href']
# print(href)
# 5. 获取所有的职位信息(纯文本)
trs = bs.select('tr')
for tr in trs:
infos = list(tr.stripped_strings)
print(infos)
print('='*30)
print('职位名称:',infos[0])
print('职位类别:',infos[1])
print('人数:',infos[2])
print('地点:',infos[3])
print('发布时间:',infos[4])
re库
导入库
import re
re语法使用一:
import re
# 1.匹配某个字符串
# text = 'hello'
# rest = re.match('he',text)
# print(rest.group())
#2. .点,匹配任意字符
# text = "a\nd"
# ret = re.match('.',text)
# print(ret.group())
# 3. \d:匹配任意的数字( 0 - 9 )
# text = "+"
# text = "9+10"
# rest = re.match('\d',text)
# print(rest.group())
# 4. \D:匹配任意的非数字
# text = "a2"
# rest = re.match('\D',text)
# print(rest.group())
# 5. \s:匹配空白字符(\n,\t,\r,空格)
# text = "\r"
# rest = re.match('\s',text)
# print(rest.group())
# 6. \w:匹配 a-z,A-Z,数字和下划线
# text = "adf"
# rest = re.match('\w',text)
# print(rest.group())
#7. \W 与 \w相反
# text = "|"
# rest = re.match('\W',text)
# print(rest.group())
# 8. []组合的方式,只要满足中括号中的字符,就可以匹配
# text = "0731-88888888asfa"
# ret = re.match('[\d\-]+',text)
# print(ret.group())
# 8.1. 中括号的形式代替\d
# text = "09"
# ret = re.match('[0-9]',text)
# print(ret.group())
# 8.2. 中括号的形式代替\D
# text = "1"
# ret = re.match('[^0-9]',text)
# print(ret.group())
# 8.3. 中括号的形式代替\w
# text = "_"
# ret = re.match('[a-zA-Z0-9_]',text)
# print(ret.group())
# 8.4. 中括号的形式代替\W
# text = "0"
# ret = re.match('[^a-zA-Z0-9_]',text)
# print(ret.group())
匹配多个字符
# 9. *:可以匹配0或者任意多个字符
# text = "abcd"
# rest = re.match('\s*',text)
# print(rest.group())
# 10. +:匹配1个或者多个字符
# text = "+abcd"
# rest = re.match('\w+',text)
# print(rest.group())
# 11. ?:匹配一个或者0个 ( 1.没有 2.只有一个)
# text = "abcd"
# rest = re.match('\w?',text)
# print(rest.group())
# 12.{m}:匹配m个字符
# text = 'abcd'
# rest = re.match('\w{2}',text)
# print(rest.group())
# 13. {m,n}:匹配 m - n 个字符
# text = 'abcd'
# rest = re.match('\w{2,5}',text)
# print(rest.group())
小案例
# 14.验证手机号码
# text = "12578900980"
# rest = re.match('1[34578]\d{9}',text)
# print(rest.group())
# 15. 验证邮箱
# text = "2214866337@qq.com"
# rest = re.match('\w+@[a-z0-9]+\.[a-z]+',text)
# print(rest.group())
# 16. 验证URL
# text = "https://baike.baidu.com/item/Python/407313?fr=aladdin"
# rest = re.match('(http|https|ftp)://[^\s]+',text) # ():匹配内容 []:匹配范围
# print(rest.group())
# 17. 验证身份证:
# text = "31131118908123230X"
# ret = re.match('\d{17}[\dxX]',text)
# ret2 = re.match('\d{17}[\d|x|X]',text)
# print(ret.group(),ret2.group())
#
# 18. ^(脱字号),表示以...开头:
# text = "hello"
# ret = re.search('^h',text)
# print(ret.group())
# 19. $:表示以...结尾:
# text = "xxx@163.com"
# ret = re.match('\w+@163.com$',text)
# print(ret.group())
# 20. |:匹配多个字符串或者表达式:
# text = "https"
# rest = re.match('(ftp|http|https)$',text)
# print(rest.group())
# 21:贪婪模式与非贪婪模式:
# text = "0123456"
# rest = re.match('\d+',text)
# print("贪婪模式= ",rest.group())
#
# text = "<h1>标题</h1>"
# ret = re.match('<.+?>',text)
# print("非贪婪模式= ",ret.group())
# 22:匹配0-100之间的数字
# # 可以出现的:1,2,3,10,100,99
# # 有三种情况:1,99,100
# # 不可以出现的:09,101
#
# text = '99'
# rest = re.match('[1-9]\d?$|100$',text)
# print(rest.group())
原声字符 与 转义字符
# import re
# # text = "apple price is $299" # 匹配 $299
# # ret = re.search("\$\d+",text) # $:在正则中有特殊意义,需转义 \ => \$
# # print(ret.group())
#
# # r = raw = 原生的
# # text = '\n'
# # print(text)
#
#
# text = "\c" #= '\n'
# # python:'\\n' = \n
# # \\\\n =》 \\n
# # \\c
#
# # 正则表达式中:\n =
# # \\n =》 \n
# # \\c =》 \c
#
# rest = re.match(r'\\c',text)
# print(rest.group())
分组
import re
# text = "apple's price $99,orange's price is $10"
# ret = re.search('.*(\$\d+).*(\$\d+)',text)
# print('分组原字符串:',ret.group(0)) # ret.group(0) = ret.group()
# print('某个分组的值:',ret.group(1))
# print('某个分组的值:',ret.group(2))
# print("分组 = ",ret.group(1,2))
# print('所有的子分组都拿出来:',ret.groups())
find_all函数
text = "apple's price $99,orange's price is $10"
ret = re.findall('\$\d+',text) # 查找所有符合条件的值,放在列表中
print('findall()函数: ',ret)
sub函数
# text = "apple's price $99,orange's price is $10"
# ret = re.sub('\$\d+',"0",text) # 把符合条件的值,替换
# print('sub()函数: ',ret)
html = """
<dd class="job_bt">
<h3 class="description">职位描述:</h3>
<div>
<p>参与公司新一代面向生命科学行业云服务应用及平台的开发。</p>
<p><br></p>
<p>【工作职责】</p>
<p>云服务软件产品的架构设计与开发</p>
<p>与设计、产品及前端人员沟通,保证产品的质量和开发进度</p>
<p>研究新兴技术,对产品进行持续优化</p>
<p><br></p>
<p>【职位要求】</p>
<p>计算机相关专业本科及以上学历</p>
<p>对常见数据结构和面向对象设计有深入理解</p>
<p>熟练掌握Python语言,3年以上实际经验</p>
<p>熟悉Python Web开发框架如Django</p>
<p>熟练掌握数据库开发和设计</p>
<p>基本的英文读写能力</p>
</div>
</dd>
"""
# ret = re.sub('<.+?>',"",html)
# print(ret)
split函数
# text = "hello&world ni hao"
# ret = re.split('[^a-zA-Z]',text)
# print('split分割函数: ',ret)
compile()预编译函数
# compile(): 预编译函数,用来写 正则 ; 调用时 直接把对象传入即可
# text = "the number is 20.50"
# # r = re.compile('\d+\.?\d*')
# r = re.compile(r"""
# \d+ # 小数点前面的数字
# \.? # 小数点本身
# \d* # 小数点后面的数字
# """,re.VERBOSE)
# ret = re.search(r,text)
# print(ret.group())
数据存储
json库
"""
在 Python 中。只有基本数据类型才能转换成 JSON 格式的字符串:
即: int 、 float 、 str 、 list 、 dict 、 tuple 。
"""
字典和列表转JSON
## 将Python对象转换为 json字符串 ; 字典和列表转JSON:
# import json
# books = [
# {
# 'title': '钢铁是怎样练成的',
# 'price': 9.8
# },
# {
# 'title': '红楼梦',
# 'price': 9.9
# }
# ]
# json_str = json.dumps(books,ensure_ascii=False)
# print(json_str)
写入json文件
## 将json数据直接 dump 到文件中:
# import json
# books = [
# {
# 'title': '钢铁是怎样练成的',
# 'price': 9.8
# },
# {
# 'title': '红楼梦',
# 'price': 9.9
# }
# ]
# with open('books.json','w',encoding='utf-8') as fp:
# # 因为 json 在 dump 的时候,只能存放 ascii 的字符,因此会将中文进行转义,这时候我们可以使用 ensure_ascii=False 关闭这个特性
# json.dump(books,fp,fp,ensure_ascii=False)
#
JSON转字典和列表
## 将一个json字符串load成Python对象:
# import json
# json_str = '[{"title": "钢铁是怎样练成的", "price": 9.8}, {"title": "红楼梦", "price": 9.9}]'
# books = json.loads(json_str,encoding='utf-8')
# print(type(books))
# print(books)
读取json文件
## 直接从文件中读取json:
import json
with open('books.json','r',encoding='utf-8') as fp:
json_str = json.load(fp)
print(json_str)
csv库
导入库
import csv
读取csv文件
############## 读取csv文件:reader()、DictReader() ###############
import csv
## 读取csv文件:
## 获取数据的时候,就要通过下表来获取数据
def read_csv_demo1():
with open('stock.csv', 'r') as fp:
# reader是一个迭代器
reader = csv.reader(fp)
# next(reader)
for x in reader:
name = x[3]
volumn = x[-1]
print({'name': name, 'volumn': volumn})
## 读取csv文件:
## 可以使用 DictReader,在获取数据的时候通过标题:
def read_csv_demo2():
with open('stock.csv','r') as fp:
# 使用DictReader创建的reader对象
# 不会包含标题那行的数据
# reader是一个迭代器,遍历这个迭代器,返回来的是一个字典。
reader = csv.DictReader(fp)
for x in reader:
value = {"name":x['secShortName'],'volumn':x['turnoverVol']}
print(value)
写入数据到csv文件
############## 写入数据到csv文件::writerow()、DictWriter() ###############
import csv
## 写入csv文件:
## writerow ,这个是写入一行。一个是 writerows ,这个是写入多行
def write_csv_demo1():
headers = ['username', 'age', 'height']
values = [
('張三', 18, 180),
('李四', 19, 190),
('王五', 20, 160)
]
with open('classroom.csv', 'w', encoding='utf-8', newline='') as fp:
writer = csv.writer(fp)
writer.writerow(headers)
writer.writerows(values)
## 写入csv文件:
## 使用字典的方式把数据写入进去。这时候就需要使用 DictWriter
def write_csv_demo2():
headers = ['username', 'age', 'height']
values = [
{'username':'张三','age':18,'height':180},
{'username':'李四','age':19,'height':190},
{'username':'王五','age':20,'height':160}
]
with open('classroo1.csv','w',encoding='utf-8',newline='') as fp:
writer = csv.DictWriter(fp,headers)
# 写入表头数据的时候,需要调用writeheader方法
writer.writeheader()
writer.writerows(values)
mysql库
连接数据库
import pymysql
database = {
'host':'127.0.0.1',
'port':3306,
'user':'python',
'password':'pythonvip',
'database':'spider_db'
}
"""
# cursor.execute(sql)
# 插入、删除、更新。 都需要执行commit操作 conn.commit() 提交执行结果、conn.close()关闭连接
"""
# 连接数据库
conn = pymysql.connect(**database)
# 获取游标:拥有操作 mysql的 权限和方法
cursor = conn.cursor()
print(cursor)
增
# sql_insert_1 = "insert into spider_tb(name,sex,age) values('xiaoguo','女',26)" # 编写 SQL语句
# sql_insert_1 = cursor.execute(sql_insert_1) # 执行 SQL数据库 语句
# conn.commit() # 提交执行结果
# conn.close() # 关闭连接
删
# sql_delete = 'delete from spider whwere id = {}'
# cursor.execute(sql_delete.format('1'))
# conn.commit()
# conn.close()
改
# sql_update = 'update spider set name={} where name={}'
# cursor.execute(sql_delete.sql_update('C#','Java'))
# conn.commit()
# conn.close()
查
######## all ########
# sql_select_all = "select * from spider"
# result = cursor.execute(sql_select_all)
# print(result)
# conn.close()
######## where ########
# sql_select_where = "select name,sex,age from spider where id=2"
# result = cursor.execute(sql_select_where)
# print(result)
# conn.close()
######## fetchone ########
# sql_select_fetchone = "select * from spider"
# cursor.execute(sql_select_fetchone)
# while True:
# result = cursor.fetchone()
# if result:
# print(result)
# else:
# break
#
# conn.close()
######## fetchall ########
# sql_select_fetchall = "select * from spider"
# cursor.execute(sql_select_fetchall)
# results = cursor.fetchall()
# for result in results:
# print(result)
# conn.close()
######## fetchmany ########
# sql_select_fetchmany = "select * from spider"
# cursor.execute(sql_select_fetchmany)
# results = cursor.fetchmany(3)
# for result in results:
# print(result)
# conn.close()
mongodb库
连接
import pymongo
#获取连接mongodb对象
client = pymongo.MongoClient("127.0.0.1",port= 27017)
连接数据库与表
# 获取数据库[1.有则连接,2.无则-创建并连接]
db = client.study
# 获取数据库中的集合[理解为: MySQL中的表]
collection = db.table
增
# 1.单行写入
# collection.insert({"username":'guokaichong'})
# 2.多行写入
# collection.insert_many([
# {
# "username":"aaa",
# 'age': 18
# },
# {
# "username":"bbb",
# 'age': 20
# },
# {
# "username":"guokaichong",
# 'age': 20,
# 'job':'python工程师'
# },
# ])
删
#1.单行删除
# collection.delete_one({"username":"guokaichong"})
#2.多行删除
# collection.delete_many({"username":"hackers"})
改
#1.单行修改
# collection.update_one({"username":'bbb'},{"$set":{"username":"hackers"}})
#.2多行修改
# collection.update_many({'username':'aaa'},{"$set":{"username":'hackers'}})
查
# 1.find方法:获取集合中所以的数据
# cursor = collection.find()
# for x in cursor:
# print(x)
### 2.获取集合中 一条数据
# result = collection.find_one({"age":20})
# print(result)
excel库
读取 Excel 文件
import xlrd
workbook = xlrd.open_workbook("成绩表.xlsx")
sheet相关操作
"""
获取 Sheet :
一个 Excel 中可能有多个 Sheet ,那么可以通过以下方法来获取想要的 Sheet 信息:
1. sheet_names :获取所有的 sheet 的名字。
2. sheet_by_index :根据索引获取 sheet 对象。
3. sheet_by_name :根据名字获取 sheet 对象。
4. sheets :获取所有的 sheet 对象。
5. sheet.nrows :这个 sheet 中的行数。
6. sheet.ncols :这个 sheet 中的列数。
"""
##1.获取所有sheet 表头的名字
# sheets = workbook.sheet_names()
# print("获取所以sheet 表头的名字",sheets)
##2.根据索引获取sheet
# for index in range(3):
# sheet = workbook.sheet_by_index(index)
# print(type(sheet))
# print(sheet.name)
##3.# 根据名称获取sheet
# sheet = workbook.sheet_by_name('1班')
# print(sheet.name)
##4.# 获取所有的sheet对象
# for sheet in workbook.sheets():
# print(sheet.name)
##5.获取这个sheet中的行数和列数
# sheet0 = workbook.sheet_by_index(0)
# print("行数:%d"%sheet0.nrows)
# print('列数:%d'%sheet0.ncols)
#
Cell相关操作
"""
获取Cell及其属性:
每个 Cell 代表的是表格中的一格。以下方法可以方便获取想要的 cell :
1. sheet.cell(row,col) :获取指定行和列的 cell 对象。
2. sheet.row_slice(row,start_col,end_col) :获取指定行的某几列的cell对象。
3. sheet.col_slice(col,start_row,end_row) :获取指定列的某几行的cell对象。
4. sheet.cell_value(row,col) :获取指定行和列的值。
5. sheet.row_values(row,start_col,end_col) :获取指定行的某几列的值。
6. sheet.col_values(col,start_row,end_row) :获取指定列的某几行的值。
"""
sheet = workbook.sheet_by_index(0)
##使用cell方法获取指定的cell对象
# cell = sheet.cell(0,0) # 第几行,第几列
# print(type(cell))
# print(cell)
##使用row_slice获取第0行的1-2列的cell对象
# cells = sheet.row_slice(0,1,3) # 第几行,第几列,到第几列
# total = sum([cell.value for cell in cells ])
# print(cells,total)
##使用col_slice获取第0列的1-2行的cell对象
# cells = sheet.col_slice(0,1,3)
# print(cells)
# cells = sheet.col_slice(1,1,sheet.nrows)
# avg = sum([cell.value for cell in cells])/len(cells)
# print(cells,avg)
# scores = sheet.col_values(1,1,sheet.nrows)
# avg = sum(scores)/len(scores)
# print(avg)
Cell的数据类型
"""
Cell的数据类型:
1. xlrd.XL_CELL_TEXT(Text) :文本类型。
2. xlrd.XL_CELL_NUMBER(Number) :数值类型。
3. xlrd.XL_CELL_DATE(Date) :日期时间类型。
4. xlrd.XL_CELL_BOOLEAN(Bool) :布尔类型。
5. xlrd.XL_CELL_BLANK :空白数据类型。
"""
sheet = workbook.sheet_by_index(0)
# xlrd.XL_CELL_TEXT(Text) :文本类型。
# cell = sheet.cell(0,0)
# print(cell.ctype)
# print(xlrd.XL_CELL_TEXT)
# xlrd.XL_CELL_NUMBER(Number) :数值类型
# cell = sheet.cell(1,1)
# print(cell.ctype)
# print(xlrd.XL_CELL_NUMBER)
# xlrd.XL_CELL_DATE(Date) :日期时间类型
# cell = sheet.cell(19,0)
# print(cell.ctype)
# print(xlrd.XL_CELL_DATE)
# xlrd.XL_CELL_BOOLEAN(Bool)
# cell = sheet.cell(19,1)
# print(cell.ctype)
# print(xlrd.XL_CELL_BOOLEAN)
# xlrd.XL_CELL_BLANK :空白数据类型
# cell = sheet.cell(19,2)
# print(cell.ctype)
# print(xlrd.XL_CELL_EMPTY)
写入Excel
写入 Excel 步骤如下:
1. 导入 xlwt 模块。
2. 创建一个 Workbook 对象。
3. 创建一个 Sheet 对象。
4. 使用 sheet.write(row,col,data) 方法把数据写入到 Sheet 下指定行和列中。如果想要在原
来 workbook 对象上添加新的 cell ,那么需要调用 put_cell 来添加。
5. 保存成 Excel 文件。
"""
# import xlwt
# import random
# workbook = xlwt.Workbook(encoding='utf-8')
# sheet = workbook.add_sheet("成绩表")
# # 添加表头
# fields = ['数学','英语','语文']
# for index,field in enumerate(fields):
# sheet.write(0,index,field)
# # 随机的添加成绩
# for row in range(1,10):
# for col in range(3):
# grade = random.randint(0,100)
# sheet.write(row,col,grade)
# workbook.save("abc.xls")
编辑 Excel 文件
"""
编辑 Excel 文件:
如果想要在原来已经存在的 Excel 文件中添加新的行或者新的列,那么需要采
用 put_cell(row,col,type,value,xf_index) 来添加进去,最后再放到 xlwt 创建的 workbook 中,
然后再保存进去
"""
import xlrd
import xlwt
workbook = xlrd.open_workbook("成绩表.xlsx")
rsheet = workbook.sheet_by_index(0) # 从下标为 0 位置开始 读取 sheet表
#
# # 添加 总分成绩
# rsheet.put_cell(0,4,xlrd.XL_CELL_TEXT,"总分",None)
# for row in range(1,rsheet.nrows):
# grade = sum(rsheet.row_values(row,1,4))
# rsheet.put_cell(row,4,xlrd.XL_CELL_TEXT,grade,None)
#
# # 添加每个科目的平均分成绩
# total_rows = rsheet.nrows
# total_cols = rsheet.ncols
# for col in range(1,total_cols):
# grades = rsheet.col_values(col,1,total_rows)
# avg_grade = sum(grades)/len(grades)
# print(type(avg_grade))
# rsheet.put_cell(total_rows,col,xlrd.XL_CELL_NUMBER,avg_grade,None)
#
# # 重新写入一个 Excel 文件数据
# wwb = xlwt.Workbook(encoding='utf-8')
# wsheet = wwb.add_sheet("1班学生成绩")
# for row in range(rsheet.ncols):
# for col in range(rsheet.ncols):
# wsheet.write(row,col,rsheet.cell_value(row,col))
#
# wwb.save("abc.xls")
案例
import xlrd
import xlwt
rwb = xlrd.open_workbook("成绩表.xlsx")
rsheet = rwb.sheet_by_index(0)
# 添加总分的cell
rsheet.put_cell(0,4,xlrd.XL_CELL_TEXT,"总分",None)
# 添加总分的数据
nrows = rsheet.nrows
ncols = rsheet.ncols
for row in range(1,nrows):
scores = rsheet.row_values(row,1,4)
rsheet.put_cell(row,4,xlrd.XL_CELL_NUMBER,sum(scores),None)
# 添加每个科目的平均分
for col in range(1,rsheet.ncols):
scores = rsheet.col_values(col,1,nrows)
avg = sum(scores)/len(scores)
rsheet.put_cell(nrows,col,xlrd.XL_CELL_NUMBER,avg,None)
# 编辑的实质:读取->编辑->写入一个新的excel文件
wwb = xlwt.Workbook(encoding='utf-8')
wsheet = wwb.add_sheet("xxx")
for row in range(rsheet.nrows):
for col in range(rsheet.ncols):
value = rsheet.cell_value(row,col)
wsheet.write(row,col,value)
wwb.save("新成绩表.xls")
进阶
多线程
多线程介绍
"""
多线程介绍:
多线程是为了同步完成多项任务,通过提高资源使用效率来提高系统的效率。线程是在同一时间需
要完成多项任务的时候实现的。
最简单的比喻多线程就像火车的每一节车厢,而进程则是火车。车厢离开火车是无法跑动的,同理
火车也可以有多节车厢。多线程的出现就是为了提高效率。同时它的出现也带来了一些问题。
threading 模块是 python 中专门提供用来做多线程编程的模块。threading 模块中最常用的类是 Thread ;
使用 threading.enumerate() 函数便可以看到当前线程的数量。
"""
传统的方式
# def coding():
# for x in range(3):
# print('正在写代码%s'%x)
# time.sleep(1)
#
# def drawing():
# for x in range(3):
# print('正在画图%s' % x)
# time.sleep(1)
#
#
# def main():
# coding()
# drawing()
#
# if __name__ == '__main__':
# main()
采用多线程的方式
# import time
# import threading
#
# def conding():
# for x in range(3):
# print('正在写代码%s'%threading.current_thread())
# time.sleep(1)
#
#
# def drawing():
# for x in range(3):
# print('正在画图%s' % threading.current_thread())
# time.sleep(1)
#
#
# def main():
# t1 = threading.Thread(target=conding)
# t2 = threading.Thread(target=drawing)
#
# t1.start()
# t2.start()
#
# print(threading.enumerate()) #使用 threading.enumerate() 函数便可以看到当前线程的数量。
#
#
# if __name__ == '__main__':
# main()
继承自 threading.Thread 类
"""
继承自 threading.Thread 类:
为了让线程代码更好的封装。可以使用 threading 模块下的 Thread 类,继承自这个类,然后实
现 run 方法,线程就会自动运行 run 方法中的代码
"""
# import threading
# import time
#
# class CodinThread(threading.Thread):
# def run(self):
# for x in range(3):
# print('正在写代码%s'%threading.current_thread())
# time.sleep(1)
#
# class DrawingThread(threading.Thread):
# def run(self):
# print('正在画图%s' % threading.current_thread())
# time.sleep(1)
#
#
# def main():
# t1 = CodinThread()
# t2 = DrawingThread()
#
# t1.start()
# t2.start()
#
# if __name__ == '__main__':
# main()
多线程共享全局变量的问题
"""
多线程共享全局变量的问题:
多线程都是在同一个进程中运行的。因此在进程中的全局变量所有线程都是可共享的。这就造成了
一个问题,因为线程执行的顺序是无序的。有可能会造成数据错误:
结果 :因为多线程运行的不确定性。因此最后的结果可能是随机的
"""
# import threading
#
# tickets = 0
# def get_ticket():
# global tickets
# for x in range(1000000):
# tickets += 1
# print('tickets:%d'%tickets)
#
# def main():
# for x in range(2):
# t = threading.Thread(target=get_ticket)
# t.start()
# if __name__ == '__main__':
# main()
锁机制
"""
锁机制:
为了解决以上使用共享全局变量的问题。 threading 提供了一个 Lock 类,这个类可以在某个线
程访问某个变量的时候加锁,其他线程此时就不能进来,直到当前线程处理完后,把锁释放了,其
他线程才能进来处理。
"""
# import threading
#
# VALUE = 0
# gLock = threading.Lock()
#
# def add_value():
# global VALUE
# gLock.acquire()
# for x in range(1000000):
# VALUE += 1
# gLock.release()
# print('value:%d'%VALUE)
# def main():
# for x in range(2):
# t = threading.Thread(target=add_value)
# t.start()
# if __name__ == '__main__':
# main()
Lock版本生产者和消费者模式
"""
Lock版本生产者和消费者模式:
生产者和消费者模式是多线程开发中经常见到的一种模式。生产者的线程专门用来生产一些数据,
然后存放到一个中间的变量中。消费者再从这个中间的变量中取出数据进行消费。但是因为要使用
中间变量,中间变量经常是一些全局变量,因此需要使用锁来保证数据完整性。以下是使
用 threading.Lock 锁实现的“生产者与消费者模式”的一个例子:
# """
# import threading
# import random
# import time
#
# gMoney = 1000
# gLock = threading.Lock()
# gTimes = 0
#
# class Producer(threading.Thread):
# def run(self):
# global gMoney
# global gLock
# global gTimes
# while True:
# money = random.randint(100, 1000)
# gLock.acquire()
# if gTimes >= 10:
# gLock.release()
# break
# gMoney += money
# print('%s当前存入%s元钱,剩余%s元钱' % (threading.current_thread(), money, gMoney))
# gTimes += 1
# time.sleep(0.5)
# gLock.release()
#
# class Consumer(threading.Thread):
# def run(self):
# global gMoney
# global gLock
# global gTimes
# while True:
# money = random.randint(100, 500)
# gLock.acquire()
# if gMoney > money:
# gMoney -= money
# print('%s当前取出%s元钱,剩余%s元钱' % (threading.current_thread(), money, gMoney))
# time.sleep(0.5)
# else:
# if gTimes >= 10:
# gLock.release()
# break
# print("%s当前想取%s元钱,剩余%s元钱,不足!" % (threading.current_thread(),money,gMoney))
# gLock.release()
#
# def main():
# for x in range(5):
# Consumer(name='消费者线程%d'%x).start()
#
# for x in range(5):
# Producer(name='生产者线程%d'%x).start()
#
# if __name__ == '__main__':
# main()
Condition版的生产者与消费者模式
Condition版的生产者与消费者模式:
Lock 版本的生产者与消费者模式可以正常的运行。但是存在一个不足,在消费者中,总是通
过 while True 死循环并且上锁的方式去判断钱够不够。上锁是一个很耗费CPU资源的行为。因此
这种方式不是最好的。还有一种更好的方式便是使用 threading.Condition 来实
现。 threading.Condition 可以在没有数据的时候处于阻塞等待状态。一旦有合适的数据了,还可
以使用 notify 相关的函数来通知其他处于等待状态的线程。这样就可以不用做一些无用的上锁和
解锁的操作。可以提高程序的性能。首先对 threading.Condition 相关的函数做个介
绍, threading.Condition 类似 threading.Lock ,可以在修改全局数据的时候进行上锁,也可以
在修改完毕后进行解锁。以下将一些常用的函数做个简单的介绍:
1. acquire :上锁。
2. release :解锁。
3. wait :将当前线程处于等待状态,并且会释放锁。可以被其他线程使
用 notify 和 notify_all 函数唤醒。被唤醒后会继续等待上锁,上锁后继续执行下面的代
码。
4. notify :通知某个正在等待的线程,默认是第1个等待的线程。
5. notify_all :通知所有正在等待的线程。 notify 和 notify_all 不会释放锁。并且需要在 release 之前调用。
# import threading
# import random
# import time
#
# gMoney = 1000
# gCondition = threading.Condition()
# gTimes = 0
# gTotalTimes = 5
#
# class Producer(threading.Thread):
# def run(self):
# global gMoney
# global gCondition
# global gTimes
# while True:
# money = random.randint(100, 1000)
# gCondition.acquire()
# if gTimes >= gTotalTimes:
# gCondition.release()
# print('当前生产者总共生产了%s次'%gTimes)
# break
# gMoney += money
# print('%s当前存入%s元钱,剩余%s元钱' % (threading.current_thread(), money, gMoney))
# gTimes += 1
# time.sleep(0.5)
# gCondition.notify_all()
# gCondition.release()
#
# class Consumer(threading.Thread):
# def run(self):
# global gMoney
# global gCondition
# while True:
# money = random.randint(100, 500)
# gCondition.acquire()
# # 这里要给个while循环判断,因为等轮到这个线程的时候
# # 条件有可能又不满足了
# while gMoney < money:
# if gTimes >= gTotalTimes:
# gCondition.release()
# return
# print('%s准备取%s元钱,剩余%s元钱,不足!'%(threading.current_thread(),money,gMoney))
# gCondition.wait()
# gMoney -= money
# print('%s当前取出%s元钱,剩余%s元钱' % (threading.current_thread(), money, gMoney))
# time.sleep(0.5)
# gCondition.release()
#
# def main():
# for x in range(5):
# Consumer(name='消费者线程%d'%x).start()
#
# for x in range(2):
# Producer(name='生产者线程%d'%x).start()
#
# if __name__ == '__main__':
# main()
Queue线程安全队列
"""
Queue线程安全队列:
在线程中,访问一些全局变量,加锁是一个经常的过程。如果你是想把一些数据存储到某个队列
中,那么Python内置了一个线程安全的模块叫做 queue 模块。Python中的queue模块中提供了同
步的、线程安全的队列类,包括FIFO(先进先出)队列Queue,LIFO(后入先出)队列
LifoQueue。这些队列都实现了锁原语(可以理解为原子操作,即要么不做,要么都做完),能够
在多线程中直接使用。可以使用队列来实现线程间的同步。相关的函数如下:
1. 初始化Queue(maxsize):创建一个先进先出的队列。
2. qsize():返回队列的大小。
3. empty():判断队列是否为空。
4. full():判断队列是否满了。
5. get():从队列中取最后一个数据。
6. put():将一个数据放到队列中。
"""
from queue import Queue
import time
import threading
# q = Queue(4)
# for x in range(4):
# print( q.put(x))
#
# for x in range(4):
# print(q.get())
### 小案例;
# def set_value(q):
# index = 0
# while True:
# q.put(index)
# index += 1
# time.sleep(3)
#
# def get_value(q):
# while True:
# print(q.get())
#
# def main():
# q = Queue(4)
# t1 = threading.Thread(target=set_value,args=[q])
# t2 = threading.Thread(target=get_value,args=[q])
#
# t1.start()
# t2.start()
#
#
# if __name__ == '__main__':
# main()
selenium自动化
介绍与应用
"""
动态网页数据抓取
什么是AJAX:
AJAX(Asynchronouse JavaScript And XML)异步JavaScript和XML。过在后台与服务器进行少
量数据交换,Ajax 可以使网页实现异步更新。这意味着可以在不重新加载整个网页的情况下,对
网页的某部分进行更新。传统的网页(不使用Ajax)如果需要更新内容,必须重载整个网页页面。
因为传统的在传输数据格式方面,使用的是 XML 语法。因此叫做 AJAX ,其实现在数据交互基本
上都是使用 JSON 。使用AJAX加载的数据,即使使用了JS,将数据渲染到了浏览器中,在 右键->
查看网页源代码 还是不能看到通过ajax加载的数据,只能看到使用这个url加载的html代码。
获取ajax数据的方式:
1. 直接分析ajax调用的接口。然后通过代码请求这个接口。
2. 使用Selenium+chromedriver模拟浏览器行为获取数据。
"""
"""
Selenium+chromedriver获取动态数据:
Selenium 相当于是一个机器人。可以模拟人类在浏览器上的一些行为,自动处理浏览器上的一些
行为,比如点击,填充数据,删除cookie等。 chromedriver 是一个驱动 Chrome 浏览器的驱动程
序,使用他才可以驱动浏览器。当然针对不同的浏览器有不同的driver。以下列出了不同浏览器及
其对应的driver
"""
快速入门
"""
快速入门:
现在以一个简单的获取百度首页的例子来讲下 Selenium 和 chromedriver 如何快速入门:
"""
# import os
# from selenium import webdriver
#
#
# # chromedriver的绝对路径
# driver_path = os.path.abspath('phantomjs.exe') # chrome.exe
# # 初始化一个driver,并指定chromedriver的路径
# driver = webdriver.PhantomJS(executable_path=driver_path)
# # 请求网页
# driver.get('https://www.baidu.com')
# # 通过page_source 获取网页源代码
# print(driver.page_source)
selenium常用操作
"""
selenium常用操作:
关闭页面:
1. driver.close() :关闭当前页面。
2. driver.quit() :退出整个浏览器。
"""
# from selenium import webdriver
# import time
#
# webdriver = webdriver.PhantomJS()
# webdriver.get('https://www.baidu.com/')
# time.sleep(5)
# webdriver.quit()
定位元素
find_element_by_id :根据id来查找某个元素。等价于:
submitTag = driver.find_element_by_id('su')
submitTag1 = driver.find_element(By.ID,'su')
find_element_by_class_name :根据类名查找元素。 等价于:
submitTag = driver.find_element_by_class_name('su')
submitTag1 = driver.find_element(By.CLASS_NAME,'su')
find_element_by_name :根据name属性的值来查找元素。等价于:
submitTag = driver.find_element_by_name('email')
submitTag1 = driver.find_element(By.NAME,'email')
find_element_by_tag_name :根据标签名来查找元素。等价于:
submitTag = driver.find_element_by_tag_name('div')
submitTag1 = driver.find_element(By.TAG_NAME,'div')
find_element_by_xpath :根据xpath语法来获取元素。等价于:
submitTag = driver.find_element_by_xpath('//div')
submitTag1 = driver.find_element(By.XPATH,'//div')
find_element_by_css_selector :根据css选择器选择元素。等价于:
submitTag = driver.find_element_by_css_selector('//div')
submitTag1 = driver.find_element(By.CSS_SELECTOR,'//div')
# 要注意,find_element 是获取第一个满足条件的元素。find_elements 是获取所有满足条件的元素。
# 1. 如果只是想要解析网页中的数据,那么推荐将网页源代码扔给lxml来解析。因为lxml底层使用的是C语言,所以解析效率会更高。
# 2. 如果是想要对元素进行一些操作,比如给一个文本框输入值,或者是点击某个按钮,那么就必须使用selenium给我们提供的查找元素的方法。
"""
# from selenium import webdriver
# from lxml import etree
# from selenium.webdriver.common.by import By
#
# driver_path = r"C:\Users\Administrator\AppData\Local\Google\Chrome\Application\chrome.exe"
# driver = webdriver.PhantomJS(executable_path=driver_path)
# driver.get('https://www.baidu.com/')
#
# # html = etree.HTML(driver.page_source)
# # html.xpath("")
#
# # inputTag = driver.find_element_by_id('kw')
# # inputTag = driver.find_element_by_name('wd')
# inputTag = driver.find_elements(By.CSS_SELECTOR,".quickdelete-wrap > input")[0]
# print(inputTag)
# inputTag.send_keys('python')
操作表单元素
"""
操作表单元素:
1. 操作输入框:分为两步。第一步:找到这个元素。第二步:使用 send_keys(value) ,将数据填充进去
2. 操作checkbox:因为要选中 checkbox 标签,在网页中是通过鼠标点击的。因此想要选
中 checkbox 标签,那么先选中这个标签,然后执行 click 事件。
3. 选择select:select元素不能直接点击。因为点击后还需要选中元素。这时候selenium就专门
为select标签提供了一个类 selenium.webdriver.support.ui.Select 。将获取到的元素当成参
数传到这个类中,创建这个对象。以后就可以使用这个对象进行选择了。
4. 操作按钮:操作按钮有很多种方式。比如单击、右击、双击等。这里讲一个最常用的。就是点击。直接调用 click 函数就可以了
# 常见的表单元素:
input type='text/password/email/number'
# buttton、input[type='submit']
# checkbox:input='checkbox'
# select:下拉列表
"""
操作输入框
### 操作输入框
# from selenium import webdriver
# import time
#
# driver_path = r"D:\ProgramApp\chromedriver\chromedriver.exe"
# driver = webdriver.Chrome(executable_path=driver_path)
# driver.get('https://www.baidu.com/')
#
# inputTag = driver.find_element_by_id('kw')
# inputTag.send_keys('python')
#
# time.sleep(3)
#
# inputTag.clear()
操作checkbox
### 操作checkbox
# from selenium import webdriver
# import time
#
# driver_path = r"D:\ProgramApp\chromedriver\chromedriver.exe"
# driver = webdriver.Chrome(executable_path=driver_path)
# driver.get('https://www.douban.com/')
#
# rememberBtn = driver.find_element_by_name('remember')
# rememberBtn.click()
操作 select标签
### 操作 select标签
# from selenium import webdriver
# from selenium.webdriver.support.ui import Select
#
# driver_path = r"D:\ProgramApp\chromedriver\chromedriver.exe"
# driver = webdriver.Chrome(executable_path=driver_path)
# driver.get('http://www.dobai.cn/')
#
# selectBtn = Select(driver.find_element_by_name('jumpMenu'))
# # selectBtn.select_by_index(1)
# # selectBtn.select_by_value("http://m.95xiu.com/")
# selectBtn.select_by_visible_text("95秀客户端")
案例: 输入-信息,点击搜索
# from selenium import webdriver
# from selenium.webdriver.support.ui import Select
#
# driver_path = r"D:\ProgramApp\chromedriver\chromedriver.exe"
# driver = webdriver.Chrome(executable_path=driver_path)
# driver.get('https://www.baidu.com/')
#
# inputTag = driver.find_element_by_id('kw')
# inputTag.send_keys('python')
#
# submitTag = driver.find_element_by_id('su')
# submitTag.click()
行为链
"""
行为链:
有时候在页面中的操作可能要有很多步,那么这时候可以使用鼠标行为链类 ActionChains 来完
成。比如现在要将鼠标移动到某个元素上并执行点击事件。
还有更多的鼠标相关的操作。
click_and_hold(element):点击但不松开鼠标。
context_click(element):右键点击。
double_click(element):双击。 更多方法请参考:http://selenium�python.readthedocs.io/api.html
"""
# from selenium import webdriver
# from selenium.webdriver.common.action_chains import ActionChains
# import time
#
# driver_path = r"D:\ProgramApp\chromedriver\chromedriver.exe"
# driver = webdriver.PhantomJS(executable_path=driver_path)
# driver.get('https://www.baidu.com/')
#
# inputTag = driver.find_element_by_id('kw')
# submitBtn = driver.find_element_by_id('su')
#
# actions = ActionChains(driver)
# actions.move_to_element(inputTag)
# actions.send_keys_to_element(inputTag,'python')
# actions.move_to_element(submitBtn)
# actions.click(submitBtn)
# actions.perform() # 执行-代码
Cookie操作
"""
Cookie操作:
1. 获取所有的 cookie :
for cookie in driver.get_cookies():
print(cookie)
2. 根据cookie的key获取value:
value = driver.get_cookie(key)
3. 删除所有的cookie:
driver.delete_all_cookies()
4. 删除某个 cookie :
driver.delete_cookie(key)
"""
# from selenium import webdriver
# from selenium.webdriver.common.action_chains import ActionChains
# import time
#
# driver_path = r"D:\ProgramApp\chromedriver\chromedriver.exe"
# driver = webdriver.Chrome(executable_path=driver_path)
# driver.get('https://www.baidu.com/')
#
# for cookie in driver.get_cookies():
# print(cookie)
#
# print('='*30)
#
# print(driver.get_cookie("PSTM"))
#
# driver.delete_cookie("PSTM")
# print('='*30)
# # print(driver.get_cookie('PSTM'))
# driver.delete_all_cookies()
页面等待
"""
页面等待:
现在的网页越来越多采用了 Ajax 技术,这样程序便不能确定何时某个元素完全加载出来了。如果
实际页面等待时间过长导致某个dom元素还没出来,但是你的代码直接使用了这个WebElement,
那么就会抛出NullPointer的异常。为了解决这个问题。所以 Selenium 提供了两种等待方式:一种
是隐式等待、一种是显式等待。
隐式等待: driver.implicitly_wait(time)、
显式等待:WebDriverWait(driver, 10).until( EC.presence_of_element_located((By.ID, "myDynamicElement")))
一些其他的等待条件:presence_of_element_located:某个元素已经加载完毕了。
presence_of_all_emement_located:网页中所有满足条件的元素都加载完毕了。
element_to_be_cliable:某个元素是可以点击了。
"""
# from selenium import webdriver
# from selenium.webdriver.support.ui import WebDriverWait
# from selenium.webdriver.support import expected_conditions as EC
# from selenium.webdriver.common.by import By
#
# driver_path = r"D:\ProgramApp\chromedriver\chromedriver.exe"
# driver = webdriver.Chrome(executable_path=driver_path)
# driver.get('https://www.douban.com/')
#
# ## 隐式等待:调用 driver.implicitly_wait 。那么在获取不可用的元素之前,会先等待10秒中的时间。
# # driver.implicitly_wait(20)
#
# """
# 显示等待:显示等待是表明某个条件成立后才执行获取元素的操作。也可以在等待的时候指定
# 一个最大的时间,如果超过这个时间那么就抛出一个异常。显示等待应该使
# 用 selenium.webdriver.support.excepted_conditions 期望的条件
# 和 selenium.webdriver.support.ui.WebDriverWait 来配合完成
# """
# element = WebDriverWait(driver,10).until(
# EC.presence_of_element_located((By.ID,'form_email'))
# )
# print(element)
切换页面
"""
切换页面:
有时候窗口中有很多子tab页面。这时候肯定是需要进行切换的。 selenium 提供了一个叫
做 switch_to_window 来进行切换,具体切换到哪个页面,可以从 driver.window_handles 中找到
# 虽然在窗口中切换到了新的页面。但是driver中还没有切换。
# 如果想要在代码中切换到新的页面,并且做一些爬虫。
# 那么应该使用driver.switch_to_window来切换到指定的窗口
# 从driver.window_handlers中取出具体第几个窗口
# driver.window_handlers是一个列表,里面装的都是窗口句柄。
# 他会按照打开页面的顺序来存储窗口的句柄。
"""
# from selenium import webdriver
#
# driver_path = r"D:\ProgramApp\chromedriver\chromedriver.exe"
# driver = webdriver.Chrome(executable_path=driver_path)
# driver.get('https://www.baidu.com/')
#
# # driver.get("https://www.douban.com/")
# driver.execute_script("window.open('https://www.douban.com/')")
# print(driver.window_handles)
# driver.switch_to_window(driver.window_handles[1])
#
# print(driver.current_url)
# print(driver.page_source)
设置代理ip
"""
设置代理ip:
有时候频繁爬取一些网页。服务器发现你是爬虫后会封掉你的ip地址。这时候我们可以更改代理
ip。更改代理ip,不同的浏览器有不同的实现方式。
"""
# from selenium import webdriver
#
# driver_path = r"D:\ProgramApp\chromedriver\chromedriver.exe"
# options = webdriver.ChromeOptions()
# options.add_argument("--proxy-server=http://60.17.239.207:31032")
#
# driver = webdriver.Chrome(executable_path=driver_path,chrome_options=options)
#
# driver.get("http://httpbin.org/ip")
WebElement 元素
"""
WebElement 元素:
from selenium.webdriver.remote.webelement import WebElement 类是每个获取出来的元素的所属
类。
有一些常用的属性:
1. get_attribute:这个标签的某个属性的值。
2. screentshot:获取当前页面的截图。这个方法只能在 driver 上使用。
driver 的对象类,也是继承自 WebElement
"""
from selenium import webdriver
from selenium.webdriver.remote.webelement import WebElement
driver = webdriver.PhantomJS()
driver.get('https://www.baidu.com/')
submitBtn = driver.find_element_by_id('su')
print(type(submitBtn))
print(submitBtn.get_attribute("value"))
driver.save_screenshot('baidu.png')