介绍: 使用requests
可以模拟浏览器的请求,比起之前用到的urllib
,requests
模块的api更加便捷(本质就是封装了urllib3
)
注意:requests
库发送请求将网页内容下载下来以后,并不会执行js
代码,这需要我们自己分析目标站点然后发起新的request
请求
官网链接: http://docs.python-requests.org/en/master/
#如果查询关键词是中文或者有其他特殊符号,则不得不进行url编码
from urllib.parse import urlencode, unquote # unquote则是将url编码的解码成中文
wd='egon老师'
encode_res=urlencode({'k':wd},encoding='utf-8')
keyword=encode_res.split('=')[1]
print(keyword)
# 然后拼接成url
url='https://www.baidu.com/s?wd=%s&pn=1' %keyword
response=requests.get(url,
headers={
'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.75 Safari/537.36',
})
res1=response.text
response=requests.get('https://www.baidu.com/s',
params={
'wd':wd,
'pn':pn
},
headers={
'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.75 Safari/537.36',
})
res=unquote('%E7%87%95%E7%AA%9D')
print(res)
#通常我们在发送请求时都需要带上请求头,请求头是将自身伪装成浏览器的关键,常见的有用的请求头如下
Host
Referer
#大型网站通常都会根据该参数判断请求来源的网址
User-Agent
#客户端的型号,其中还会区分不同终端,如手机、电脑、平板
Cookie
#Cookie
信息虽然包含在请求头里,但requests
模块有单独的参数来处理他,headers={}
内就不要放它了(该字段只能放入字符串类型的cookie)
浏览器会识别请求头,不加可能会被拒绝访问
cookie参数中要传入一个字典形式中包含许多字典形式的cookie
示例:用cookie自动登录github
#登录github,然后从浏览器中获取cookies,以后就可以直接拿着cookie登录了,无需输入用户名密码
#用户名:egonlin 邮箱[email protected] 密码lhf@123
import requests
Cookies={ 'user_session':'wGMHFJKgDcmRIVvcA14_Wrt_3xaUyJNsBnPbYzEL6L0bHcfc',
}
response=requests.get('https://github.com/settings/emails',
cookies=Cookies) #github对请求头没有什么限制,我们无需定制user-agent,对于其他网站可能还需要定制
print('[email protected]' in response.text) #True
HTTP默认的请求方法就是GET
* 没有请求体
* 数据必须在1K之内!
* GET请求数据会暴露在浏览器的地址栏中
GET请求常用的操作:
1. 在浏览器的地址栏中直接给出URL,那么就一定是GET请求
2. 点击页面上的超链接也一定是GET请求
3. 提交表单时,表单默认使用GET请求,但可以设置为POST
#POST请求
(1). 数据不会出现在地址栏中
(2). 数据的大小没有上限
(3). 有请求体
(4). 请求体中如果存在中文,会使用URL编码!
!!!requests.post()用法与requests.get()完全一致,特殊的是requests.post()有一个data参数,用来存放请求体数据
抓包:需要用错误的用户名或密码登录(对于登录来说,应该输错用户名或密码然后分析抓包流程,用脑子想一想,输对了浏览器就跳转了,还分析个毛线,累死你也找不到包)
案例:github抓包并获取cookie
一 目标站点分析
浏览器输入https://github.com/login
然后输入错误的账号密码,抓包
发现登录行为是post提交到:https://github.com/session
而且请求头包含cookie
而且请求体包含:
commit:Sign in
utf8:✓
authenticity_token:lbI8IJCwGslZS8qJPnof5e7ZkCoSoMn6jmDTsL1r/m06NLyIbw7vCrpwrFAPzHMep3Tmf/TSJVoXWrvDZaVwxQ==
login:egonlin
password:123
二 流程分析
先GET:https://github.com/login拿到初始cookie与authenticity_token
返回POST:https://github.com/session, 带上初始cookie,带上请求体(authenticity_token,用户名,密码等)
最后拿到登录cookie
ps:如果密码时密文形式,则可以先输错账号,输对密码,然后到浏览器中拿到加密后的密码,这里github传输的密码是明文
import requests
import re
#第一次请求
r1=requests.get('https://github.com/login')
r1_cookie=r1.cookies.get_dict() #拿到初始cookie(未被授权)
authenticity_token=re.findall(r'name="authenticity_token".*?value="(.*?)"',r1.text)[0] #从页面中拿到CSRF TOKEN
#第二次请求:带着初始cookie和TOKEN发送POST请求给登录页面,带上账号密码
data={
'commit':'Sign in',
'utf8':'✓',
'authenticity_token':authenticity_token,
'login':'[email protected]',
'password':'alex3714'
}
r2=requests.post('https://github.com/session',
data=data,
cookies=r1_cookie
)
login_cookie=r2.cookies.get_dict()
#第三次请求:以后的登录,拿着login_cookie就可以,比如访问一些个人配置
r3=requests.get('https://github.com/settings/emails',
cookies=login_cookie)
print('[email protected]' in r3.text) #True
import requests
import re
session=requests.session()
#第一次请求
r1=session.get('https://github.com/login')
authenticity_token=re.findall(r'name="authenticity_token".*?value="(.*?)"',r1.text)[0] #从页面中拿到CSRF TOKEN
#第二次请求
data={
'commit':'Sign in',
'utf8':'✓',
'authenticity_token':authenticity_token,
'login':'[email protected]',
'password':'alex3714'
}
r2=session.post('https://github.com/session',
data=data,
)
#第三次请求
r3=session.get('https://github.com/settings/emails')
print('[email protected]' in r3.text) #True
requests.post(url='xxxxxxxx',
data={'xxx':'yyy'}) #没有指定请求头,#默认的请求头:application/x-www-form-urlencode
#如果我们自定义请求头是application/json,并且用data传值, 则服务端取不到值
requests.post(url='',
data={'':1,},
headers={
'content-type':'application/json'
})
requests.post(url='',
json={'':1,},
) #默认的请求头:application/json
respone.text
# html的文本内容
respone.content
# 整页的二进制数据,可以用来取得视频图片
response.iter_content
# 二进制流,分段式的传输过来,如较大的视频
respone.status_code
# 状态码
respone.headers
# 响应头
respone.cookies
# cookie对象 RequestsCookieJar的对象
from requests.cookies import RequestsCookieJar
# 在pycharm中用此方法点进去看源码
respone.cookies.get_dict()
# cookie对象转成字典
respone.cookies.items()
# 遍历cookie
respone.url
# 请求地址
respone.history
# 网站中各种重定向后,之前的地址的历史记录
respone.encoding
# 网站编码(大部分网站都是用的utf-8,但还是会有很少一部分用的gb2312这种,requests的默认编码为ISO-8859-1,如果不设置成gbk则中文乱码:response.encoding='gbk'
)
from requests.cookies import RequestsCookieJar
jar = RequestsCookieJar()
with open("cookie.json", "r") as fp:
cookies = json.load(fp)
for cookie in cookies:
jar.set(cookie['name'], cookie['value'])
之后就可以在请求中加入cookies=jar
来装填cookie了
requests.post(url,cookies=jar,headers=header,data=data)
import requests
response=requests.get('https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1509868306530&di=712e4ef3ab258b36e9f4b48e85a81c9d&imgtype=0&src=http%3A%2F%2Fc.hiphotos.baidu.com%2Fimage%2Fpic%2Fitem%2F11385343fbf2b211e1fb58a1c08065380dd78e0c.jpg')
with open('a.jpg','wb') as f:
f.write(response.content)
#stream参数:一点一点的取,比如下载视频时,如果视频100G,用response.content然后一下子写到文件中是不合理的
import requests
response=requests.get('https://gss3.baidu.com/6LZ0ej3k1Qd3ote6lo7D0j9wehsv/tieba-smallvideo-transcode/1767502_56ec685f9c7ec542eeaf6eac93a65dc7_6fe25cd1347c_3.mp4',
stream=True)
with open('b.mp4','wb') as f:
for line in response.iter_content():
f.write(line)
#解析json
import requests
response=requests.get('http://httpbin.org/get')
import json
res1=json.loads(response.text) #太麻烦
res2=response.json() #直接获取json数据
print(res1 == res2) #True
allow_redirects是requests发送请求时的属性
配置allow_redirects=false时遇到重定向也不会跳转,并且response.history也是个空列表
而没有配置时遇到重定向会正常跳转,response.history中也能取到历史对象
#证书验证(大部分网站都是https)
import requests
respone=requests.get('https://www.12306.cn') #如果是ssl请求,首先检查证书是否合法,不合法则报错,程序终端
#改进1:去掉报错,但是会报警告
import requests
respone=requests.get('https://www.12306.cn',verify=False) #不验证证书,报警告,返回200
print(respone.status_code)
#改进2:去掉报错,并且去掉警报信息
import requests
from requests.packages import urllib3
urllib3.disable_warnings() #关闭警告
respone=requests.get('https://www.12306.cn',verify=False)
print(respone.status_code)
#改进3:加上证书
#很多网站都是https,但是不用证书也可以访问,大多数情况都是可以携带也可以不携带证书
#知乎\百度等都是可带可不带
#有硬性要求的,则必须带,比如对于定向的用户,拿到证书后才有权限访问某个特定网站
import requests
respone=requests.get('https://www.12306.cn',
cert=('/path/server.crt',
'/path/key'))
print(respone.status_code)
官网链接: http://docs.python-requests.org/en/master/user/advanced/#proxies
代理设置:先发送请求给代理,然后由代理帮忙发送(封ip是常见的事情)
import requests
proxies={
'http':'http://egon:123@localhost:9743',#带用户名密码的代理,@符号前是用户名与密码
'http':'http://localhost:9743',
'https':'https://localhost:9743',
}
respone=requests.get('https://www.12306.cn',
proxies=proxies)
print(respone.status_code)
#支持socks代理,安装:pip install requests[socks]
import requests
proxies = {
'http': 'socks5://user:pass@host:port',
'https': 'socks5://user:pass@host:port'
}
respone=requests.get('https://www.12306.cn',
proxies=proxies)
print(respone.status_code)
高匿和透明
高匿:服务端很难取到真实的ip
透明:服务端可以取到真实的ip地址,从请求头中:X-Forwarded-For取到,Django就是从Meta中取
代理池:搞一堆代理,放到列表中,每次发请求,随机出一个(开源代理池)
ps:自己写一个django,从中用META.get('REMOTE_ADDR')
查看访问的IP,看看代理后访问的IP还是原本IP吗
#超时设置
#两种超时:float or tuple
#timeout=0.1 #代表接收数据的超时时间
#timeout=(0.1,0.2)#0.1代表链接超时 0.2代表接收数据的超时时间
import requests
respone=requests.get('https://www.baidu.com',
timeout=0.0001)
官网链接: http://docs.python-requests.org/en/master/user/authentication/
认证设置:登陆网站是,弹出一个框,要求你输入用户名密码(与alter很类似),此时是无法获取html的
但本质原理是拼接成请求头发送
# r.headers['Authorization'] = _basic_auth_str(self.username, self.password)
# 一般的网站都不用默认的加密方式,都是自己写
# 那么我们就需要按照网站的加密方式,自己写一个类似于_basic_auth_str的方法
# 得到加密字符串后添加到请求头
# r.headers['Authorization'] =func('.....')
#看一看默认的加密方式吧,通常网站都不会用默认的加密设置
import requests
from requests.auth import HTTPBasicAuth
r=requests.get('xxx',auth=HTTPBasicAuth('user','password'))
print(r.status_code)
#HTTPBasicAuth可以简写为如下格式
import requests
r=requests.get('xxx',auth=('user','password'))
print(r.status_code)
import requests
from requests.exceptions import * #可以查看requests.exceptions获取异常类型
try:
r=requests.get('http://www.baidu.com',timeout=0.00001)
except ReadTimeout:
print('===:')
# except ConnectionError: #网络不通
# print('-----')
# except Timeout:
# print('aaaaa')
except RequestException:
print('Error')
实际上用一个exception Exception as e
捕获就行了
请求中的files字段传入
import requests
files={'file':open('a.jpg','rb')}
respone=requests.post('http://httpbin.org/post',files=files)
print(respone.status_code)
Beautiful Soup
是一个可以从HTML或XML文件中提取数据的Python库.它能够通过你喜欢的转换器实现惯用的文档导航,查找,修改文档的方式.Beautiful Soup会帮你节省数小时甚至数天的工作时间.你可能在寻找 Beautiful Soup3 的文档,Beautiful Soup 3 目前已经停止开发,官网推荐在现在的项目中使用Beautiful Soup 4, 移植到BS4
pip install beautifulsoup4
#安装解析器
Beautiful Soup支持Python标准库中的HTML解析器,还支持一些第三方的解析器,其中一个是 lxml .根据操作系统不同,可以选择下列方法来安装lxml:
$ apt-get install Python-lxml
$ easy_install lxml
$ pip install lxml
另一个可供选择的解析器是纯Python实现的 html5lib , html5lib的解析方式与浏览器相同,可以选择下列方法来安装html5lib:
$ apt-get install Python-html5lib
$ easy_install html5lib
$ pip install html5lib
一般都选择使用lxml
解析器
如有如下html文本:
html_doc = """
The Dormouse's story
The Dormouse's story
Once upon a time there were three little sisters; and their names were
Elsie,
Lacie and
Tillie;
and they lived at the bottom of a well.
...
"""
#基本使用:容错处理,文档的容错能力指的是在html代码不完整的情况下,使用该模块可以识别该错误。使用BeautifulSoup解析上述代码,能够得到一个 BeautifulSoup 的对象,并能按照标准的缩进格式的结构输出
from bs4 import BeautifulSoup
soup=BeautifulSoup(html_doc,'lxml') #传入html的文本,具有容错功能
res=soup.prettify() #处理好缩进,结构化显示
print(res)
p=soup.p.name
# 对象.name
取到标签的名字
p=soup.p['class']
# class
是列表,可以有多个
name=soup.p['name']
attr=soup.p.attrs
# 所有属性放到字典中
t=soup.p.text
# 把p标签文本
+子标签文本
都拿出来
soup.p.string
# p下的文本
只有一个时,取到,否则为None
soup.p.strings
#拿到一个生成器对象, 取到p下所有的文本
内容
list(soup.p.strings)
b=soup.body.p.b
soup.p.contents
# p下所有子节点
soup.p.children
# 得到一个迭代器,包含p下所有子节点
soup.p.descendants
#获取子孙节点,p下所有的标签都会选择出来
soup.a.parent
#获取a标签的父节点
soup.a.parents
#找到a标签所有的祖先节点,父亲的父亲,父亲的父亲的父亲…挖祖坟
soup.a.next_sibling #下一个兄弟
soup.a.previous_sibling #上一个兄弟
soup.find()
:查找匹配成功的第一个标签对象源码中就是find_all()[0]
soup.find_all()
:查找所有匹配成功的标签,返回列表
from bs4 import BeautifulSoup
soup=BeautifulSoup(html_doc,'lxml')
#1、五种过滤器: 字符串、正则表达式、列表、True、方法
#1.1、字符串:即标签名
print(soup.find_all('b'))
#1.2、正则表达式
import re
print(soup.find_all(re.compile('^b'))) #找出b开头的标签,结果有body和b标签
print(soup.find_all(class_=re.compile('^s'),namd='a')) # a标签并且class匹配正则的标签
#1.3、列表:如果传入列表参数,Beautiful Soup会将与列表中任一元素匹配的内容返回.下面代码找到文档中所有标签和标签:
print(soup.find_all(['a','b']))
#1.4、True:可以匹配任何值,下面代码查找到所有的tag,但是不会返回字符串节点
print(soup.find_all(class_=True)) # 查找所有含有class的标签
print(soup.find_all(href=True)) # 查找所有含有href的标签
for tag in soup.find_all(True):
print(tag.name)
#1.5、方法:如果没有合适过滤器,那么还可以定义一个方法,方法只接受一个元素参数 ,如果这个方法返回 True 表示当前元素匹配并且被找到,如果不是则反回 False
def has_class_but_no_id(tag):
return tag.has_attr('class') and not tag.has_attr('id')
print(soup.find_all(has_class_but_no_id))
#2.1 name: 搜索name参数的值可以使任一类型的 过滤器 ,字符窜,正则表达式,列表,方法或是 True .
print(soup.find_all(name=re.compile('^t')))
#2.2、keyword: key=value的形式,value可以是过滤器:字符串 , 正则表达式 , 列表, True .
print(soup.find_all(id=re.compile('my')))
print(soup.find_all(href=re.compile('lacie'),id=re.compile('\d'))) #注意类要用class_
print(soup.find_all(id=True)) #查找有id属性的标签
#2.3、按照类名查找,注意关键字是class_,class_=value,value可以是五种选择器之一
print(soup.find_all('a',class_='sister')) #查找类为sister的a标签
print(soup.find_all('a',class_='sister ssss')) #查找类为sister和sss的a标签,顺序错误也匹配不成功
print(soup.find_all(class_=re.compile('^sis'))) #查找类为sister的所有标签
#2.4、attrs
print(soup.find_all('p',attrs={'class':'story'}))
# 有些tag属性在搜索不能使用,比如HTML5中的 data-* 属性:
data_soup = BeautifulSoup('foo!','lxml')
# data_soup.find_all(data-foo="value") #报错:SyntaxError: keyword can't be an expression
# 但是可以通过 find_all() 方法的 attrs 参数定义一个字典参数来搜索包含特殊属性的tag:
print(data_soup.find_all(attrs={"data-foo": "value"}))
# [foo!]
#2.5、text: 值可以是:字符,列表,True,正则
print(soup.find_all(text='Elsie'))
print(soup.find_all('a',text='Elsie'))
#2.6、limit参数:如果文档树很大那么搜索会很慢.如果我们不需要全部结果,可以使用 limit 参数限制返回结果的数量.效果与SQL中的limit关键字类似,当搜索到的结果数量达到 limit 的限制时,就停止搜索返回结果,只返回limit条数的标签对象
print(soup.find_all('a',limit=2))
#2.7、recursive:调用tag的 find_all() 方法时,Beautiful Soup会检索当前tag的所有子孙节点,如果只想搜索tag的直接子节点,可以使用参数 recursive=False .
print(soup.html.find_all('a'))
print(soup.html.find_all('a',recursive=False))
'''
像调用 find_all() 一样调用tag
find_all() 几乎是Beautiful Soup中最常用的搜索方法,所以我们定义了它的简写方法. BeautifulSoup 对象和 tag 对象可以被当作一个方法来使用,这个方法的执行结果与调用这个对象的 find_all() 方法相同,下面两行代码是等价的:
soup.find_all("a")
soup("a")
这两行代码也是等价的:
soup.title.find_all(text=True)
soup.title(text=True)
#该模块提供了select方法来支持css,详见官=网:https://www.crummy.com/software/BeautifulSoup/bs4/doc/index.zh.html#id37
from bs4 import BeautifulSoup
soup=BeautifulSoup(html_doc,'lxml')
soup.p.select('.sister')
soup.select('.sister span')
soup.select('#link1')
soup.select('#link1 span')
soup.select('#list-2 .element.xxx')
soup.select('#list-2')[0].select('.element')
#可以一直select,但其实没必要,一条select就可以了
soup.select('#list-2 h1')[0].attrs
soup.select('#list-2 h1')[0].get_text()
xml
解析库selenium
+半人工登录,获取cookie
-----》给requests
模块使用安装:selenium
+chromedriver
pip3 install selenium
下载chromdriver.exe
放到python
安装路径的scripts
目录中即可(或者在webdriver.Chrome(executable_path='chromedriver.exe')
传入exe的路径),版本要与自己浏览器版本吻合
国内镜像网站地址: http://npm.taobao.org/mirrors/chromedriver/
最新的版本去官网找: https://sites.google.com/a/chromium.org/chromedriver/downloads
#注意:
selenium3
默认支持的webdriver
是Firfox
,而Firefox
需要安装geckodriver
下载链接:https://github.com/mozilla/geckodriver/releases
PhantomJS
不再更新,看看即可
#安装:selenium+phantomjs
pip3 install selenium
下载phantomjs,解压后把phantomjs.exe所在的bin目录放到环境变量
下载链接:http://phantomjs.org/download.html
#验证安装
C:\Users\Administrator>phantomjs
phantomjs> console.log('egon gaga')
egon gaga
undefined
phantomjs> ^C
C:\Users\Administrator>python3
Python 3.6.1 (v3.6.1:69c0db5, Mar 21 2017, 18:41:36) [MSC v.1900 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> from selenium import webdriver
>>> driver=webdriver.PhantomJS() #无界面浏览器
>>> driver.get('https://www.baidu.com')
>>> driver.page_source
在 PhantomJS 年久失修, 后继无人的节骨眼
Chrome 出来救场, 再次成为了反爬虫 Team 的噩梦
自Google 发布 chrome 59 / 60 正式版 开始便支持Headless mode
这意味着在无 GUI 环境下, PhantomJS 不再是唯一选择
selenium+google的headless模式
#selenium:3.12.0
#webdriver:2.38
#chrome.exe: 65.0.3325.181(正式版本) (32 位)
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
chrome_options = Options()
chrome_options.add_argument('window-size=1920x3000') #指定浏览器分辨率
chrome_options.add_argument('--disable-gpu') #谷歌文档提到需要加上这个属性来规避bug
chrome_options.add_argument('--hide-scrollbars') #隐藏滚动条, 应对一些特殊页面
chrome_options.add_argument('blink-settings=imagesEnabled=false') #不加载图片, 提升速度
chrome_options.add_argument('--headless') #浏览器不提供可视化页面. linux下如果系统不支持可视化不加这条会启动失败
chrome_options.binary_location = r"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" #手动指定使用的浏览器位置
driver=webdriver.Chrome(chrome_options=chrome_options)
driver.get('https://www.baidu.com')
print('hao123' in driver.page_source)
driver.close() #切记关闭浏览器,回收资源
from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.common.by import By #按照什么方式查找,By.ID,By.CSS_SELECTOR
from selenium.webdriver.common.keys import Keys #键盘按键操作
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait #等待页面加载某些元素
browser=webdriver.Chrome(executable_path='chromedriver.exe')
try:
browser.get('https://www.baidu.com')
input_tag=browser.find_element_by_id('kw')
input_tag.send_keys('美女') #python2中输入中文错误,字符串前加个u
input_tag.send_keys(Keys.ENTER) #输入回车
#隐式等待:在查找所有元素时,如果尚未被加载,则等10秒
browser.implicitly_wait(10)
print(browser.page_source)
print(browser.current_url)
print(browser.get_cookies())
finally:
browser.close()
强调:
1. 上述均可以改写成find_element(By.ID,'kw')
的形式
2. find_elements_by_xxx
的形式是查找到多个元素,结果为列表
拿lxml中的xpath方法举例
from lxml import etree
html=etree.HTML(doc)
# html=etree.parse('search.html',etree.HTMLParser())
1 所有节点
# a=html.xpath('//*')
2 指定节点(结果为列表)
# a=html.xpath('//head')
3 子节点,子孙节点
# a=html.xpath('//div/a')
# a=html.xpath('//body/a') #无数据,只能看儿子
# a=html.xpath('//body//a')
4 父节点
# a=html.xpath('//body//a[@href="image1.html"]/..')
# a=html.xpath('//body//a[1]/..') # body下第一个a的爸爸
# 也可以这样
# a=html.xpath('//body//a[1]/parent::*')
5 属性匹配
# a=html.xpath('//body//a[@href="image1.html"]')
6 文本获取
# a=html.xpath('//body//a[@href="image1.html"]/text()')
7 属性获取
# a=html.xpath('//body//a/@href')
# # 注意从1 开始取(不是从0)
# a=html.xpath('//body//a[1]/@href') # 第一个a的网址
8 属性多值匹配
# a 标签有多个class类,直接匹配就不可以了,需要用contains
# a=html.xpath('//body//a[@class="li"]')
# a=html.xpath('//body//a[contains(@class,"li")]')
# a=html.xpath('//body//a[contains(@class,"li")]/text()')
9 多属性匹配
# a=html.xpath('//body//a[contains(@class,"li") or @name="items"]')
# a=html.xpath('//body//a[contains(@class,"li") and @name="items"]/text()')
# # a=html.xpath('//body//a[contains(@class,"li")]/text()')
10 按序选择
# a=html.xpath('//a[2]/text()')
# a=html.xpath('//a[2]/@href')
取最后一个last()
# a=html.xpath('//a[last()]/@href')
位置小于3的position()<3
# a=html.xpath('//a[position()<3]/@href')
倒数第二个last()-2
# a=html.xpath('//a[last()-2]/@href')
11 节点轴选择
ancestor:祖先节点
# 使用了* 获取所有祖先节点
# a=html.xpath('//a/ancestor::*')
# # 获取祖先节点中的div
# a=html.xpath('//a/ancestor::div')
attribute:属性值
# a=html.xpath('//a[1]/attribute::*')
child:直接子节点
# a=html.xpath('//a[1]/child::*')
descendant:所有子孙节点
# a=html.xpath('//a[6]/descendant::*')
following:当前节点之后所有节点
# a=html.xpath('//a[1]/following::*')
# a=html.xpath('//a[1]/following::*[1]/@href')
following-sibling:当前节点之后同级节点
# a=html.xpath('//a[1]/following-sibling::*')
# a=html.xpath('//a[1]/following-sibling::a')
# a=html.xpath('//a[1]/following-sibling::*[2]')
# a=html.xpath('//a[1]/following-sibling::*[2]/@href')
browser=webdriver.Chrome()
browser.get('https://www.amazon.cn/')
wait=WebDriverWait(browser,10)
wait.until(EC.presence_of_element_located((By.ID,'cc-lm-tcgShowImgContainer')))
tag=browser.find_element(By.CSS_SELECTOR,'#cc-lm-tcgShowImgContainer img')
#获取标签属性,
print(tag.get_attribute('src'))
#获取标签ID,位置,名称,大小(了解)
print(tag.id)
print(tag.location)
print(tag.tag_name)
print(tag.size)
print(tag.text)
# 标签对象可以继续查找下去
tag_a = tag.find_element_by_xpath('./a[1]') # 如xpath需要 . 开头,代表从当前位置继续
browser.close()
selenium
只是模拟浏览器的行为,而浏览器解析页面是需要时间的(执行css,js
),一些元素可能需要过一段时间才能加载出来,为了保证能查找到元素,必须等待
等待的方式分两种:
隐式等待:在browser.get('xxx')
前就设置,针对所有元素有效
显式等待:在browser.get('xxx')
之后设置,只针对某个元素有效
隐式等待示例:
browser=webdriver.Chrome()
browser.get('https://www.baidu.com')
#隐式等待:在查找所有元素时,如果尚未被加载,则等10秒
browser.implicitly_wait(10)
input_tag=browser.find_element_by_id('kw')
input_tag.send_keys('美女')
input_tag.send_keys(Keys.ENTER)
显式等待示例:
from selenium.webdriver.support.wait import WebDriverWait #等待页面加载某些元素
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By #按照什么方式查找,By.ID,By.CSS_SELECTOR
#显式等待:显式地等待10s某个元素被加载
wait=WebDriverWait(browser,10)
wait.until(EC.presence_of_element_located((By.ID,'content_left')))
input_tag.send_keys('iphone 8') # 输入
button.click() # 点击
input_tag.clear() # 清空
from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.common.by import By # 按照什么方式查找,By.ID,By.CSS_SELECTOR
from selenium.webdriver.common.keys import Keys # 键盘按键操作
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait # 等待页面加载某些元素
import time
driver = webdriver.Chrome()
driver.get('http://www.runoob.com/try/try.php?filename=jqueryui-api-droppable')
wait=WebDriverWait(driver,3)
# driver.implicitly_wait(3) # 使用隐式等待
try:
driver.switch_to.frame('iframeResult') ##切换html到iframeResult
sourse=driver.find_element_by_id('draggable')
target=driver.find_element_by_id('droppable')
#方式一:基于同一个动作链串行执行
# actions=ActionChains(driver) #拿到动作链对象
# actions.drag_and_drop(sourse,target) #把动作放到动作链中,准备串行执行,将sourse拖动到target
# actions.perform() # 执行
#方式二:不同的动作链,每次移动的位移都不同
# 基于坐标进行位移
ActionChains(driver).click_and_hold(sourse).perform() # 鼠标左键按住滑块
distance=target.location['x']-sourse.location['x'] # 需要向右位移的距离
track=0
while track < distance:
ActionChains(driver).move_by_offset(xoffset=2,yoffset=0).perform() #
track+=2
ActionChains(driver).release().perform() # 松开鼠标左键
time.sleep(10)
finally:
driver.close()
browser.execute_script('alert("hello world")') #打印警告
frame
相当于一个单独的网页,在父frame里是无法直接查看到子frame的元素的,必须switch_to_frame切到该frame下,才能进一步查找
browser.switch_to.frame('iframeResult') #切换到id为iframeResult的frame
之后browser就是这个frame下的对象了,后续再查找也是在这个frame中查找
browser.back() # 退
browser.forward() # 进
coo = browser.get_cookies() # 取得cookie字典
for i in coo:
browser.add_cookie(i) # 将cookie存入
browser.execute_script('window.open()') # 执行js:打开新的选项卡
browser.window_handles # 获取所有的选项卡
browser.switch_to_window(browser.window_handles[1]) # 选择选项卡,这里选的是第二个,从0开始算
browser.switch_to_window(browser.window_handles[0]) # 选择第一个选项卡
from selenium.common.exceptions import TimeoutException,NoSuchElementException,NoSuchFrameException
try:
browser=webdriver.Chrome()
browser.get('http://www.runoob.com/try/try.php?filename=jqueryui-api-droppable')
browser.switch_to.frame('iframssseResult')
except TimeoutException as e:
print(e)
except NoSuchFrameException as e:
print(e)
finally:
browser.close()
老样子这里跟requests一样,用Exception as e就完事了其实,若需要细粒度的可以使用上面的方法
#https://www.lagou.com/jobs/positionAjax.json?city=%E4%B8%8A%E6%B5%B7&needAddtionalResult=false
import requests
#实际要爬取的url
url = 'https://www.lagou.com/jobs/positionAjax.json?needAddtionalResult=false'
payload = {
'first': 'true',
'pn': '1',
'kd': 'python',
}
header = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36',
'Referer': 'https://www.lagou.com/jobs/list_python?labelWords=&fromSearch=true&suginput=',
'Accept': 'application/json, text/javascript, */*; q=0.01'
}
#原始的url
urls ='https://www.lagou.com/jobs/list_python?labelWords=&fromSearch=true&suginput='
#建立session
s = requests.Session()
# 获取搜索页的cookies
s.get(urls, headers=header, timeout=3)
# 为此次获取的cookies
cookie = s.cookies
# 获取此次文本
response = s.post(url, data=payload, headers=header, cookies=cookie, timeout=5).text
print(response)
#http://www.shicimingju.com/book/hongloumeng.html
import requests
from bs4 import BeautifulSoup
ret=requests.get('https://www.shicimingju.com/book/hongloumeng.html')
# print(ret.text)
soup=BeautifulSoup(ret.text,'lxml')
li_list=soup.find(class_='book-mulu').find('ul').find_all('li')
with open('hlm.txt','w',encoding='utf-8') as f:
for li in li_list:
content=li.find('a').text
url='https://www.shicimingju.com'+li.find('a').get('href')
f.write(content)
f.write('\n')
res_content=requests.get(url)
soup2=BeautifulSoup(res_content.text,'lxml')
content_detail=soup2.find(class_='chapter_content').text
f.write(content_detail)
f.write('\n')
print(content,'写入了')
# http://www.kfc.com.cn/kfccda/ashx/GetStoreList.ashx?op=keyword
import requests
header = {
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36'
}
data = {
'cname': '',
'pid': 20,
'keyword': '浦东',
'pageIndex': 1,
'pageSize': 10
}
ret = requests.post('http://www.kfc.com.cn/kfccda/ashx/GetStoreList.ashx?op=keyword', data=data, headers=header)
print(ret.json())
#https://www.qiushibaike.com/text/page/2/
import requests
from bs4 import BeautifulSoup
ret=requests.get('https://www.qiushibaike.com/text/page/2/')
# print(ret.text)
soup=BeautifulSoup(ret.text,'html.parser')
article_list=soup.find_all(class_='article')
# print(article_list)
for article in article_list:
content=article.find(class_='content').text
print(content)
print('-------')
from selenium import webdriver
import time
import json
bro=webdriver.Chrome(executable_path='chromedriver.exe')
bro.get('https://dig.chouti.com/')
bro.maximize_window() # 最大化
bro.implicitly_wait(10)
login_btn=bro.find_element_by_link_text('登录')
login_btn.click()
name_input=bro.find_element_by_name('phone')
password_input=bro.find_element_by_name('password')
name_input.send_keys('抽屉账号')
password_input.send_keys('抽屉密码')
login_real_btn=bro.find_element_by_css_selector('button.login-btn')
login_real_btn.click()
# 可能有验证码,手动搞定
time.sleep(20)
cookie=bro.get_cookies()
print(cookie)
with open('cookie.json','w') as f:
json.dump(cookie,f)
print('cookie写入到文件中了')
# 自动点赞功能
import requests
from requests.cookies import RequestsCookieJar
header = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36',
'Referer': 'https://dig.chouti.com/',
}
res = requests.get('https://dig.chouti.com/link/hot', headers=header)
print(res.json())
jar=RequestsCookieJar()
# 从文件中读出来,写到cookie中
with open('cookie.json','r') as f:
cookie_l=json.load(f)
for cookie in cookie_l:
jar.set(cookie['name'], cookie['value'])
for item in res.json()['data']:
id = item['id']
print(id)
# 点赞请求,也不能缺cookie
data={
'linkId':id
}
res = requests.post('https://dig.chouti.com/link/vote', headers=header,cookies=jar,data=data)
# res = requests.post('https://dig.chouti.com/link/vote', headers=header,data=data)
print(res.text)
from selenium import webdriver
import time
#pillow
from PIL import Image
# 引入超级鹰
from chaojiying import Chaojiying_Client
from selenium.webdriver import ActionChains
bro=webdriver.Chrome(executable_path='./chromedriver.exe')
bro.implicitly_wait(10)
try:
bro.get('https://kyfw.12306.cn/otn/resources/login.html')
bro.maximize_window() # 窗口最大化,全屏
button_z=bro.find_element_by_css_selector('.login-hd-account a')
button_z.click()
time.sleep(2)
# 截取整个屏幕
bro.save_screenshot('./main.png')
# 验证码的位置和大小
img_t=bro.find_element_by_id('J-loginImg')
print(img_t.size)
print(img_t.location)
size=img_t.size
location=img_t.location
img_tu = (int(location['x']), int(location['y']), int(location['x'] + size['width']), int(location['y'] + size['height']))
# # 抠出验证码
# #打开
img = Image.open('./main.png')
# 抠图
fram = img.crop(img_tu)
# 截出来的小图
fram.save('code.png')
# 调用超级鹰破解
chaojiying = Chaojiying_Client('超级鹰账号', '超级鹰密码', '903641') #用户中心>>软件ID 生成一个替换 96001,最后这个是破解模板的ID
im = open('code.png', 'rb').read() #本地图片文件路径 来替换 a.jpg 有时WIN系统须要//
# print(chaojiying.PostPic(im, 9004))
## 返回结果如果有多个 260,133|123,233,处理这种格式[[260,133],[123,233]]
res=chaojiying.PostPic(im, 9004)
print(res)
result=res['pic_str']
all_list = []
if '|' in result:
list_1 = result.split('|')
count_1 = len(list_1)
for i in range(count_1):
xy_list = []
x = int(list_1[i].split(',')[0])
y = int(list_1[i].split(',')[1])
xy_list.append(x)
xy_list.append(y)
all_list.append(xy_list)
else:
x = int(result.split(',')[0])
y = int(result.split(',')[1])
xy_list = []
xy_list.append(x)
xy_list.append(y)
all_list.append(xy_list)
print(all_list)
# 用动作链,点击图片
# [[260,133],[123,233]]
for a in all_list:
x = a[0]
y = a[1]
ActionChains(bro).move_to_element_with_offset(img_t, x, y).click().perform()
time.sleep(1)
username=bro.find_element_by_id('J-userName')
username.send_keys('12306账号')
password=bro.find_element_by_id('J-password')
password.send_keys('12306密码')
time.sleep(3)
submit_login=bro.find_element_by_id('J-login')
submit_login.click()
time.sleep(3)
print(bro.get_cookies())
time.sleep(10)
bro.get('https://www.12306.cn/index/')
time.sleep(5)
except Exception as e:
print(e)
finally:
bro.close()
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
# 定义爬取函数
def get_goods(bro):
# 滑倒屏幕底部
bro.execute_script('scroll(0,document.body.scrollHeight)')
li_list = bro.find_elements_by_class_name('gl-item')
for li in li_list:
try:
img_url = li.find_element_by_css_selector('.p-img>a>img').get_attribute('src')
if not img_url:
img_url = li.find_element_by_css_selector('.p-img>a>img').get_attribute('data-lazy-img')
img_url = 'https:' + img_url
name = li.find_element_by_css_selector('.p-name em').text
url = li.find_element_by_css_selector('.p-img>a').get_attribute('href')
price = li.find_element_by_css_selector('.p-price i').text
commit = li.find_element_by_css_selector('.p-commit a').text
print('''
商品名称:%s
商品价格:%s
商品链接:%s
图片链接:%s
商品评论数:%s
''' % (name, price, url, img_url, commit))
except Exception as e:
continue
# 点击下一页
next = bro.find_element_by_partial_link_text('下一页')
next.click()
# 再解析下一页的内容
get_goods(bro)
bro = webdriver.Chrome(executable_path='chromedriver.exe')
try:
bro.get('https://www.jd.com/')
# 隐式等待
bro.implicitly_wait(10)
search_in = bro.find_element_by_id('key')
search_in.send_keys('男士内衣')
search_in.send_keys(Keys.ENTER) # 敲击回车
# bro.page_source--->bs4--lxml
get_goods(bro)
except Exception as e:
print(e)
finally:
bro.close()