requests库
import requests
#get请求及常用参数
#status_code 返回码
#reason 响应结果
#text 响应内容
#json() json响应内容
headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.79 Safari/537.36'}
cookies = {'username': 'duson', 'password': 'duson0.0'}
method_get = requests.get('http://httpbin.org/get', params={'a':'1', 'b':'2'}, headers=headers, cookies=cookies)
method_post = requests.post('http://httpbin.org/post', data={'aa':'1', 'bb':'2'}, params={'a':'1', 'b':'2'}, headers=headers, cookies=cookies)
#print(method_get.status_code, method_get.reason, method_get.text)
print('get请求', method_get.json())
print('post请求', method_post.json())
#使用requests.Session()对象请求
#创建一个Session对象
rs = requests.Session()
#session对象会保存服务器返回的set-cookies头信息内的内容
rs.get('http://httpbin.org/cookies/set/userid/12345678')
rs.get('http://httpbin.org/cookies/set/token/xxxxxxxx')
#下一次请求会将s本地所有r的cookies信息自动添加到请求头信息
r = rs.get('http://httpbin.org/cookies')
print('检查session中的cookies',r.json())
#在requests中使用代理
print('不使用代理', requests.get('http://httpbin.org/ip').json())
print('使用代理', requests.get('http://httpbin.org/ip', proxies = {
'http': 'http://120.24.189.164:41801'
}).json())
XPath语法:
使用方式:
使用//获取整个页面中的元素,然后写标签名,然后再写谓词进行提取
//div[@class="abc"]
谓语:
路径表达式 | 描述 |
//div/a[1] | 选择div下的第一个a标签 |
//div/a[last()] | 选择div下的倒数第一个a标签 |
//div/a[position()<3] | 选择div下的前面两个a标签 |
//div[contains(@class,'abc')] | 选择div中带有class=abc的标签 |
//div[@class] | 选择所有带class属性的标签 |
//div[@class="abc"] | 选择所有带class属性并且值为abc的标签 |
//div[@*] | *为通配符意为获取所有 |
//div[@class="abc"] | //div[@class="def"] | |或,用于选择多个路径 |
//div[@class="abc" and @id="def"] | and 且,or或 |
//a/@href | 获取所有a标签的href的值 |
//a/text() | 获取所有a标签的文本 |
//a/[not(@class)] | 获取不包含class的a标签 |
//a/[not(@class) and not(@id)] | 获取不包含class且不包含id的a标签 |
//a/[not(contains(@class,'expire'))] | 获取不包含class="expire"的a标签 |
需要注意的知识点:
1,//标签名[contains(@属性名,"属性值")]:有时候某个属性中含了多个值,可使用contains进行提取
<div class="abc def"></div>
//div[contains(@class,'abc')]
2,谓词中的下标是从1开始而不是0
lxml库
安装:pip install lxml
基本使用:
用于解析html代码,并且在解析html代码的时候,如果html代码不规范,会自动补全
1.通过requests库爬下来的数据的解释
from lxml import etree
text = '''
<div class="s-menus-outer">
<div id="s_menus_wrapper" class="menus-wrapper"><span class="s-menu-item s-opacity-white-background current" data-id="2">
推荐 </span><span class="s-menu-item s-opacity-white-background" data-id="1"> 导航 </span></div>
<div class="s-bg-space s-opacity-white-background"></div><span class="s-menu-music" data-id="3"></span>
</div>
'''
#利用etree.HTML,将字符串解析为HTML文档
html = etree.HTML(text)
#按字符串序列化HTML文档
#tostring解释出来的如果是byte类型的字符串则需要添加encoding指定编码后用decode解码,方便查看
result = etree.tostring(html,encoding='utf-8').decode('utf-8')
print(result)
2.解释文件中的html代码
from lxml import etree
html = etree.parse('text.html')
#按字符串序列化HTML文档
#tostring解释出来的如果是byte类型的字符串则需要添加encoding指定编码后用decode解码,方便查看
result = etree.tostring(html,encoding='utf-8').decode('utf-8')
print(result)
3.解释文件中的html代码时默认是xml解析器,html出现标签不完整和开始结束标签不匹配时需要自己指定解析器修复
from lxml import etree
#定义html解析器
parser = etree.HTMLParser(encoding='utf-8')
#etree.parse第二个参数为指定解析器
html = etree.parse('text.html',parser=parser)
result = etree.tostring(html,encoding='utf-8').decode('utf-8')
print(result)
lxml结合xpath注意事项:
1.使用xpath语法,element.xpath返回的是一个列表
import lxml from etree
parser = etree.HTMLParser(encoding='utf-8')
htmlElement = etree.parse('test.html',parser=parser)
tags = htmlElement.xpath('//div')
from urllib.parse import urlparse
import os
from lxml import etree
import requests
requ = requests.get('http://www.xiachufang.com/')
#定义html解析器
requestTest = etree.HTML(requ.text)
imgs = requestTest.xpath('//img')
#创建文件夹
'''
os.path.join(path1[, path2[, ...]]) 把目录和文件名合成一个路径
os.path.isdir(path) 判断路径是否为目录
os.path.dirname(path) 返回文件的路径不算文件名
'''
image_dir = os.path.join(os.curdir,'images')
if not os.path.isdir(image_dir):
os.mkdir(image_dir)
urls = []
for v in imgs[::-1]:
url = ''
if v.xpath('@data-src'):
url = v.xpath('@data-src')[0].split('@')[0]
else:
url = v.xpath('@src')[0].split('@')[0]
o = urlparse(url)
filename = o.path[1:]
if filename: #判断是否存在文件,防止因不存在文件名而错误
filepath = os.path.join(image_dir,filename) #即将保存的完整路径
if not os.path.isdir(os.path.dirname(filepath)): #防止文件有子目录
os.mkdir(os.path.dirname(filepath)) #创建目录
res = requests.get(url) #请求文件
with open(filepath,'wb') as f:
for c in res.iter_content(1024): #循环进制内容,每次写入1m
f.write(c)
2.获取某个标签的属性的值:
href = htmlElement.xpath("//a/@href")
3.获取标签内的文本,xpath内添加"."代表在获取当前标签下的标签
text = htmlElement.xpath("./td[2]/text()")[0]
beautifulSoup
4个常用的对象:Tag,NavigatableString,BeautifulSoup,Comment
find和find_all和select
from bs4 import BeaudifulSoup
#标签太多,省略一万个
html = '''
<ul>
<li id="bs4liid1" class="bs4li">
<a href="baidu.com">百度</a>
</li>
<li id="bs4liid2" class="bs4li">
<a href="qq.com">腾讯</a>
</li>
<li id="bs4liid3" class="bs4li">
<a href="alibaba.com">阿里</a>
</li>
</ul>
'''
soup = BeaudifulSoup(html,'lxml')
#find获取第一个符合条件的标签
li1 = soup.find('li',id='bs4liid1')
li2 = soup.find('li',attrs={'id':'bs4liid2'})
li3 = sooup.select_one('li#bs4liid1')
#find_all获取所有符合条件的标签
lis1 = soup.find_all('li',class_='bs4li',limit=3) #limist指定提取多少个
lis2 = soup.find_all('li',attrs={'class':'bs4li'})
lis3 = soup.select('li.bs4li',limit=3) #select支持css选择器语法,limist指定提取多少个
#获取属性
aList = soup.find_all('a')
for a in aList:
href1 = a['href']
href2 = a.attrs['href']
#提取文本,string,strings,stripped_strings,get_text
#string:获取某个标签下的非标签字符串,返回字符串
#strings:获取甘个标签下的子孙标签下的非标签字符串,返回列表生成器
#stripped_strings:获取某个标签下的子孙标签下的非标签字符串,会去掉空白字符,返回列表生成器
#get_text:获取某个标签下的子孙非标签字符串,返回普通字符串而不是列表
正则表达式
语法 | 说明 | 表达式 | 完整匹配的字符 |
字符 | |||
. | 匹配任意除换行符“\n”外的字符,re.DOTALL模式下也可匹配\n | a.c | abc |
\ | 转义字符,用于\*?+.^|...... | a\.c | a.c |
[] | 字符集,用于匹配范围,第一个字符是^则表示取反 | a[a-zA-Z]c | aac,azc,aAc,aZc |
预定义字符集,可写在[]中 | |||
\d | 匹配0-9的数字 | a\dc | a1c,a9c |
\D | 匹配非0-9的字符 [^0-9] | a\Dc | abc,azc,aAc,aZc |
\w | 单词0-9,a-z,A-Z,_ | a\wc | a0c,a9c,aac,azc,aAc,aZc |
\W | 非的0-9,a-z,A-Z,_单词 [^\w] | a\Wc | a@c,a c |
\s | 匹配空白字符包括\n,\t,\r,\f,\v,空格 | a\sc | a c |
\S | 匹配非空白字符 [^\s] | a\Sc | abc |
\u4E00-\u9FA5 | 匹配中文文字 | a哈a | 哈 |
数量词,用在字符或()后 | |||
? | 匹配前一个字符0或1次或取消贪婪模式 | abc? | ab,abc |
+ | 匹配前一个字符1或无限次 | abc+ | abc,abcc.abccc |
* | 匹配前一个字符0或无限次 | abc* | ab,abc,abcccc |
{m} | 匹配前一个字符m次 | abc{3} | abccc |
{m,n} | 匹配前一个字符m到n次,省略m为0到n次,省略n为m到无限次 | abc{1,3} | abc.abcc.abccc |
??,+?,*?,{m,n}? | 例* + ? {m,n}变成非贪梦模式 | ||
逻辑,分组 | |||
| | 代表左右表达式任意匹配一个 | abc|def | abc,def |
() | 分组 | ||
边界匹配(不消耗待匹配字符串中的字符) | |||
^ | 匹配字符串开头,在多行模式中匹配每一行的开头 | ^abc | abc |
$ | 匹配字符串末尾,在多行模式中匹配每一行的末尾 | $abc | abc |
\A | 仅匹配字符串开头 | \Aabc | abc |
\Z | 仅匹配字符串末尾 | abc\Z | abc |
\b | 匹配\w和\W之间 | a\b!bc | a!bc |
\B | [^\b] | a\Bbc | abc |
特殊构造,不作为分组 | |||
(?=...) | 之后的字符串内容需要匹配表达式才能成功匹配,不消耗字符串 | a(?=\d) | 后面是数字的a |
(?!...) | 之后的字符串内容需要不匹配表达式才能成功匹配,不消耗字符串 | a(?!\d) | 后面不是数字的a |
(?<=...) | 之前的字符串内容需要匹配表达式才能成功匹配,不消耗字符串 | (?<=]d)a | 前面是数字的a |
(?<!...) | 之前的字符串内容需要匹配表达式才能成功匹配,不消耗字符串 | (?<!]d)a | 前面不是数字的a |
Python 的 re 模块
常用函数,compile,match,search,findall,finditer,split,sub
- match 方法:从起始位置开始查找,一次匹配
- search 方法:从任何位置开始查找,一次匹配
- findall 方法:全部匹配,返回列表
- finditer 方法:全部匹配,返回迭代器
- split 方法:分割字符串,返回列表
- sub 方法:替换字符串
re.DOTALL模式,match,search,findall,finditer
re 模块的一般使用步骤如下:
-
使用
compile()
函数将正则表达式的字符串形式编译为一个Pattern
对象 -
通过
Pattern
对象提供的一系列方法对文本进行匹配查找,获得匹配结果,一个 Match 对象。 - 最后使用
Match
对象提供的属性和方法获得信息,根据需要进行其他的操作
match方法:match(string, start, end)
import re
pattern = re.compile(r'\d+')
m1 = pattern.match('one12twothree34four') # 查找头部,没有匹配
m2 = pattern.match('one12twothree34four',2,10) # 从e开始匹配,匹配失败
m3 = pattern.match('one12twothree34four',3,10) # 从1开始匹配,匹配成功
m3.group(0) # 0可省略 打印结果为12
m3.start(0) # 0可省略 打印结果为3
m3.end(0) # 0可省略 打印结果为5
m3.span(0) # 0可省略 打印结果为(3,5)
在上面,当匹配成功时返回一个 Match 对象,其中:
-
group([group1, …]) 方法用于获得一个或多个分组匹配的字符串,当要获得整个匹配的子串时,可直接使用 group() 或 group(0);
-
start([group]) 方法用于获取分组匹配的子串在整个字符串中的起始位置(子串第一个字符的索引),参数默认值为 0;
- end([group]) 方法用于获取分组匹配的子串在整个字符串中的结束位置(子串最后一个字符的索引+1),参数默认值为 0;
- span([group]) 方法返回 (start(group), end(group))。
search 方法:search(string, start, end)
search 方法用于查找字符串的任何位置,它也是一次匹配,只要找到了一个匹配的结果就返回,而不是查找所有匹配的结果,它的一般使用形式如下:
search(string[, pos[, endpos]])
string 是待匹配的字符串,pos 和 endpos 是可选参数,指定字符串的起始和终点位置,默认值分别是 0 和 len (字符串长度)。
当匹配成功时,返回一个 Match 对象,如果没有匹配上,则返回 None。
import re
pattern = re.compile('\d+')
m = pattern.search('one12twothree34four') # 这里如果使用 match 方法则不匹配
m
<_sre.SRE_Match object at 0x10cc03ac0>
m.group()
'12'
m = pattern.search('one12twothree34four', 10, 30) # 指定字符串区间
m
<_sre.SRE_Match object at 0x10cc03b28>
m.group()
'34'
m.span()
(13, 15)
findall 方法
获得所有匹配的结果。
findall 方法的使用形式如下:
findall(string[, pos[, endpos]])
string 是待匹配的字符串,pos 和 endpos 是可选参数,指定字符串的起始和终点位置,默认值分别是 0 和 len (字符串长度)。
findall 以列表形式返回全部能匹配的子串,如果没有匹配,则返回一个空列表。
import re
pattern = re.compile(r'\d+') # 查找数字
result1 = pattern.findall('hello 123456 789')
result2 = pattern.findall('one1two2three3four4', 0, 10)
print(result1) # ['123456', '789']
print(result2) # ['1', '2']
finditer 方法
finditer 方法的行为跟 findall 的行为类似,也是搜索整个字符串,获得所有匹配的结果。但它返回一个顺序访问每一个匹配结果(Match 对象)的迭代器。
import re
pattern = re.compile(r'\d+')
result_iter1 = pattern.finditer('hello 123456 789')
result_iter2 = pattern.finditer('one1two2three3four4', 0, 10)
print(type(result_iter1)
print(type(result_iter2)
for m1 in result_iter1: # m1 是 Match 对象
print('matching string: {}, position: {}'.format(m1.group(), m1.span()))
for m2 in result_iter2:
print('matching string: {}, position: {}'.format(m2.group(), m2.span()))
split 方法
split 方法按照能够匹配的子串将字符串分割后返回列表
split(string[, maxsplit])
maxsplit 用于指定最大分割次数,不指定将全部分割。
看看例子:
import re
p = re.compile(r'[\s\,\;]+')
print(p.split('a,b;; c d'))
执行结果:
['a', 'b', 'c', 'd']
sub 方法
sub 方法用于替换字符串
sub(repl, string[, count])
repl 可以是字符串也可以是一个函数:
-
如果 repl 是字符串,则会使用 repl 去替换字符串每一个匹配的子串,并返回替换后的字符串,另外,repl 还可以使用 id 的形式来引用分组,但不能使用编号 0;
-
如果 repl 是函数,这个方法应当只接受一个参数(Match 对象),并返回一个字符串用于替换(返回的字符串中不能再引用分组)。
- count 用于指定最多替换次数,不指定时全部替换。
import re
p = re.compile(r'(\w+) (\w+)') # \w = [A-Za-z0-9]
s = 'hello 123, hello 456'
print(p.sub(r'hello world', s)) # 使用 'hello world' 替换 'hello 123' 和 'hello 456'
print(p.sub(r'\2 \1', s)) # 引用分组
def func(m):
return 'hi' + ' ' + m.group(2)
print(p.sub(func, s))
print(p.sub(func, s, 1)) # 最多替换一次
执行结果:
hello world, hello world
123 hello, 456 hello
hi 123, hi 456
hi 123, hello 456
匹配中文
在某些情况下,我们想匹配文本中的汉字,有一点需要注意的是,中文的 unicode 编码范围 主要在 [u4e00-u9fa5],这里说主要是因为这个范围并不完整,比如没有包括全角(中文)标点,不过,在大部分情况下,应该是够用的。
假设现在想把字符串 title = u'你好,hello,世界' 中的中文提取出来,可以这么做:
import re
title = u'你好,hello,世界'
pattern = re.compile(ur'[\u4e00-\u9fa5]+')
result = pattern.findall(title)
print(result)
注意到,我们在正则表达式前面加上了两个前缀 ur,其中 r 表示使用原始字符串,u 表示是 unicode 字符串。
执行结果:
[u'\u4f60\u597d', u'\u4e16\u754c']
注意:贪婪模式与非贪婪模式
- 贪婪模式:在整个表达式匹配成功的前提下,尽可能多的匹配 ( * );
- 非贪婪模式:在整个表达式匹配成功的前提下,尽可能少的匹配 ( ? );
- Python里数量词默认是贪婪的。
示例一 : 源字符串:abbbc
- 使用贪婪的数量词的正则表达式
ab*
,匹配结果: abbb。*
决定了尽可能多匹配 b,所以a后面所有的 b 都出现了。
- 使用非贪婪的数量词的正则表达式
ab*?
,匹配结果: a。即使前面有
*
,但是?
决定了尽可能少匹配 b,所以没有 b。
示例二 : 源字符串:aa<div>test1</div>bb<div>test2</div>cc
-
使用贪婪的数量词的正则表达式:
<div>.*</div>
-
匹配结果:
<div>test1</div>bb<div>test2</div>
这里采用的是贪婪模式。在匹配到第一个“
</div>
”时已经可以使整个表达式匹配成功,但是由于采用的是贪婪模式,所以仍然要向右尝试匹配,查看是否还有更长的可以成功匹配的子串。匹配到第二个“</div>
”后,向右再没有可以成功匹配的子串,匹配结束,匹配结果为“<div>test1</div>bb<div>test2</div>
”
-
使用非贪婪的数量词的正则表达式:
<div>.*?</div>
-
匹配结果:
<div>test1</div>
正则表达式二采用的是非贪婪模式,在匹配到第一个“
</div>
”时使整个表达式匹配成功,由于采用的是非贪婪模式,所以结束匹配,不再向右尝试,匹配结果为“<div>test1</div>
”。
json读写
- dump() 将python对象写入文件
- dumps() 将python对象转换成json
- load(),
- loads()
dump()、dumps()
import json
person= [
{'name':'张三','age':20,'height':180},
{'name':'李四','age':21,'height':170},
{'name':'王五','age':22,'height':160}
]
# dumps函数将python对象转换为json字符串
json_str = json.dumps(person)
# dump把json写入文件
with open('person.json','w',encoding='utf-8') as fp:
#json在dump的时候默认存放ascii字符,把ensure_ascii=False后正常保存中文
json.dump(person,fp,ensure_ascii=False)
load()、loads()
import json
json_str = '[{"name":"张三","age":20},{"name":"李四","age":21},{"name":"王五","age":22}]'
person1 = json.loads(json_str)
print(person1)
width open('person.json','r',encoding='utf-8') as fp:
person2 = json.load(fp)
print(person2)
for person in person2:
print(person)
cvs文件读写
- reader() 以列表形式读取
- DictReader() 以字典形式读取
- writer() 以列表形式写入
- DictWriter() 以字典形式写入
reader()、DictReader()
import csv
def list_read_csv():
with open('stock.csv', 'r') as fp:
#返回结果reader是一个迭代器
reader = csv.reader(fp)
# 每执行一次next方法,reader就会跳一行
next(reader)
for x in reader:
print(x)
def dict_read_csv():
with open('stock.csv', 'r') as fp:
#使用DictReader创建的reader对象不会包含标题那行的数据,返回结果是个迭代器
reader = csv.DictReader(fp)
for x in reader:
print(x)
writer()、DictWriter()
import csv
headers = ['name','age','height']
values = [('张三',20,'180'),('李四',21,'170'),('王五',22,'160')]
# 写入csv文件时默认每一行会插入一条空行,newline=''去掉空行
with open('person1.cvx','w',encoding='utf-8',newline='') as fp:
writer = csv.writer(fp)
# 写入表头,writerow写入一行,writerows写入多行
writer.writerow(headers)
writer.writerows(values)
values2 = [
{'name':'张三','age':20,'height':'180'},
{'name':'李四','age':21,'height':'170'},
{'name':'王五','age':22,'height':'160'}
]
with open('persons2.cvs','w',newline='',encoding='utf-8') as fp:
# DictWriter需要先传入表头,然后执行writeheader写入表头
writer = csv.DictWriter(fp,headers)
writer.writeheader()
writer.writerows(values2)
seleninum + chromedriver获取动态数据
根据电脑上的chrome浏览版本下载,下载地址:http://chromedriver.storage.googleapis.com/index.html
安装配置
- 安装selenium pip install selenium
- 安装chromedriver 把chromedriver.exe放到不需要权限的纯英文目录下
from selenium import webdriver
#chromedriver的绝对路径
driver_path = r"D:\Anaconda3\Scripts\chromedriver.exe"
#初始化一个driver,并指定chromedriver的路径
driver = webdriver.Chrome(executable_path=driver_path)
#请求网页
driver.get("https://www.baidu.com")
#通过page_source获取网页源代码
print(driver.page_source)
#打印当前driver页面url
print(driver.current_url)
#关闭当前页面
#driver.close()
#关闭整个浏览器
#driver.quit()
定位元素
#find_element_by_id : 根据id来查找某个元素
tag1 = driver.find_element_by_id('name')
#find_element_by_class_name : 根据类名查找元素,find_elements_by_class_name获取所有
tag2 = driver.find_element_by_class_name('name')
#find_element_by_name : 根据name属性的值来查找元素,find_elements_by_name获取所有
tag3 = driver.find_element_by_name('value')
#find_element_by_tag_name : 根据标签名来查找元素,find_elements_by_tag_name获取所有
tag4 = driver.find_element_by_tag_name('div')
#find_element_by_css_selector: 根据css选择器选择元素,find_elements_by_css_selector获取所有
tag5 = driver.find_element_by_css_selector('.className > childrenName')
#find_element_by_xpath: 根据xpath方法来获取元素
tag6 = driver.find_element_by_xpath('//div')
操作表单元素
1、操作输入框,文本框
inputTag = driver.find_element_by_id('inp')
#对输入框填充数据
inputTag.send_keys('python')
#清空输入框内容
inputTag.clear()
2、操作checkbox,radio用法相同
box = driver.find_element_by_name('boxName')
box.click()
3、操作select
from selenium.webdriver.support.ui import Select
#选择select标签,然后使用Select()创建对象
selectTag = Select(driver.find_element_by_tag_name('select'))
#通过下标选择
selectTag.select_by_index(1)
#通过value选择
selectTag.select_by_value
#通过可视文本选择
selectTag.select_by_visible_text('文本值')
#取消所有选中项
selectTag.deselect_all()
行为链(多用于自动化测试)
通过行为链类ActionChains完成一系列动作
from selenium.webdriver.common.action_chains import ActionChains
inputTag = driver.find_element_by_id('kw')
subitTag = driver.fiind_element_by_id('su')
#创建对象
actions = ActionChains(driver)
#移动鼠标到对应标签
actions.move_to_element(inputTag)
#对input框输入值
actions.send_keys_to_element(inputTag,'python')
#移动鼠标到提交按钮
actions.move_to_element(submitTag)
#点击按钮
actions.click(submitTag)
actions.perform()
#更多操作 文档:https://selenium-python.readthedocs.io/api.html
Cookie操作
#获取所有cookie
for cookie in driver.get_cookies():
print(cookie)
#根据key获取cookie(key)
value = driver.get_cookie(key)
#删除所有cookie
driver.delete_all_cookies()
#删除某个cookie
driver.delete_cookie(key)
页面等待
用于解决因ajax加载页面导致dom元素未加载所产生的错误,一隐式等待,二显式等待
1、隐式等待:调用driver.implicitly_wait,等10秒后再获取元素
driver = webdriver.Chrome(executable_path=driver_path)
driver.implicitly_wait(10)
driver.get("https://www.baidu.com/")
2、显示等待:根据某个条件成立后才执行获取元素的操作。也可以指定一个最大等待时间,如果超这个时间就抛出异常
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
driver_path = r"D:\Anaconda3\Scripts\chromedriver.exe"
driver = webdriver.Chrome(executable_path=driver_path)
driver.get("https://www.douban.com/")
element = WebDriverWait(driver,30).until(
EC.presence_of_element_located((By.TAG_NAME,'iframe'))
)
# frame()查找和定位iframe框架的方法(switch_to)
driver.switch_to.frame(driver.find_element_by_tag_name('iframe'))
driver.find_element_by_class_name('account-tab-account').click()
username = WebDriverWait(driver, 10).until(lambda driver: driver.find_element_by_css_selector('#username'))
pwd = WebDriverWait(driver, 10).until(lambda driver: driver.find_element_by_css_selector('#password'))
username.send_keys('373423271@qq.com')
pwd.send_keys('duson0.0')
3、一些其他的等条件
- presence_of_element_located:某个元素已经加载完毕
- presence_of_all_element_located:网页中所有满足条件的元素都加载完毕
- element_to_be_cliable:某个元素可以点击了
- 更多条件参考地址:http://selenium-python.readthedocs.io/waits.html
切换页面
注:打开新窗口后需要通过window_handles获取窗口列表,再用switch_to.window()切换页面,否则页面不变
#excute_script执行js代码,使用js代码打开新窗口
driver.execute_script('window.open("http://www.duban.com")')
#切换到新页面,window_handles获取页面
driver.switch_to.window(driver.window_handles[1])
print(driver.window_handles)
print(driver.current_url)
print(driver.page_source)
设置代理ip
使用代理ip防止爬虫被封
from selenium import webdriver
#创建options对象
options = webdriver.ChromeOptions()
#添加代理配置
options.add_argument("--proxy-server=http://61.164.39.68:53281")
driver_path = r"D:\Anaconda3\Scripts\chromedriver.exe"
#通过options参数传入
driver = webdriver.Chrome(executable_path=driver_path,options=options)
driver.get("http://httpbin.org/ip")
WebElement元素
from selenium.webdriver.remote.webelement import WebElement类是每个获取出来的元素的所属类
有一些常用属性:
- 1.get_attribute :获取某个标签的某个属性值
- 2. screentshot:获取当前页面的截图。这个方法只能在driver上用
- 3.driver的对象类,也是继承自WebElement类
其他方法可查看源代码
from selenium import webdriver
driver_path = r"D:\Anaconda3\Scripts\chromedriver.exe"
driver = webdriver.Chrome(executable_path=driver_path)
driver.get("https://www.baidu.com/")
submitBtn = driver.find_element_by_id('su')
driver.save_screenshot('baidu.png')
print(type(submitBtn))
print(submitBtn.get_attribute("value"))