- 爬虫:通过编写程序员模拟浏览器上网,然后让其去互联网上爬取/获取数据的过程。
- 分类(使用场景):
- 通用爬虫:爬取一整张页面数据。“抓取系统”
- 聚焦爬虫:爬取的就是页面中指定的内容
- 增量式爬虫:用来检测网站数据更新的情况。只爬取网站最新更新的数据。
- 协议:客户端和服务器端进行数据交互的某种形式
- 请求头信息:
- User-Agent:请求载体的身份标识
- Connection:close
- 响应头信息:
- Content-Type:
- https:安全
- 加密方式:
- 对称秘钥加密:
- 非对称秘钥加密:
- 证书秘钥加密:
反爬机制: 反反爬:
1.robots.txt协议 忽略此协议 2.UA测验 在请求参数中添加headers(模拟网站发请求) 3.验证码 云打码、超级鹰、打码兔 4.cookie 用session发送请求 5、检测ip 找个代理(透明(能发现你的ip)、匿名(可以发现代理服务器的ip,不能发现你的ip)、高匿(既不能发现你的也不能发现代理的ip)) 6、动态参数 动态获取 7、动态加载 selenium滑动加载
- requests模块:网络请求的一个模块。
- 环境的安装:pip install requests
- reqeusts模块的作用:
- 模拟浏览器发请求。
- requests模块的编码流程:
- 1.指定url
- 2.发起请求
- 3.获取响应数据
- 4.持久化存储
案例1:爬取sogou首页文本内容
#导入模块
import requests
#指定url
url = 'https://www.sogou.com/'
#发起请求:get方法的返回值就是一个响应对象
response = requests.get(url=url)
#获取响应数据:text属性返回的是字符串形式的响应数据
page_text = response.text
#step_4:持久化存储
with open('./sogou.html','w',encoding='utf-8') as fp:
fp.write(page_text)
案例2:爬取搜狗指定词条搜索后的页面数据
import requests
url = 'https://www.sogou.com/web'
#处理url请求的参数
wd = input('enter a word:')
param = {
'query':wd
}
response = requests.get(url=url,params=param)
#设置响应数据的编码
response.encoding = 'utf-8'
page_text = response.text
print(page_text)
name = wd+'.html'
with open(name,'w',encoding='utf-8') as fp:
fp.write(page_text)
print(name,'爬取成功!')
- 编码流程:
- 指定url
- 发起请求
- 获取响应数据
- 数据解析
- 持久化存储
- 如何实现数据解析
- 正则
- bs4
- xpath
- 数据解析的原理
- 实现标签定位
- 将标签中存储的文本内容或者相关的属性值进行提取
案例:如何爬取一张图片数据(方法一)
import requests
url = 'https://pic.qiushibaike.com/system/pictures/12176/121763419/medium/GKAGFQXQTVNBYK37.jpg'
headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36'
}
response = requests.get(url=url,headers=headers)
#content二进制形式的图片数据
img_data = response.content
with open('./qiutu.jpg','wb') as fp:
fp.write(img_data)
案例:如何爬取一张图片数据(方法二)
import requests from urllib import request url = 'https://pic.qiushibaike.com/system/pictures/12176/121763419/medium/GKAGFQXQTVNBYK37.jpg' request.urlretrieve(url=url,filename='./qiubai.jpg')#filename存储文件路径
案例:爬取所有的糗图数据
import requests
import os
import re
from urllib import request
url = 'https://www.qiushibaike.com/pic/'
headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36'
}
page_text = requests.get(url=url,headers=headers).text
#创建一个文件夹用来存储下载好的所有的图片
if not os.path.exists('./qiutu'): #指定路径
os.mkdir('./qiutu')
#进行数据解析(img标签)
ex = '<div class="thumb">.*?<img src="(.*?)" alt.*?</div>'
img_src_list = re.findall(ex,page_text,re.S)
for src in img_src_list:
src = 'https:'+src
name = src.split('/')[-1]
img_path = './qiutu/'+name
request.urlretrieve(src,img_path)
print(name,'下载成功!')
print('下载完毕,共下载图片数量为:',len(img_src_list))
- 环境安装:
- pip install bs4
- pip install lxml
- bs4解析原理
- 实例化一个BeautifulSoup对象,必须把即将被解析的页面源码加载到该对象中
- 调用该对象中相关的属性或者方法进行标签的定位和内容的提取
- 如何实例化一个BeautifulSoup对象
- 本地加载:
- soup = BeautifulSoup(fp,'lxml')
- 网络加载:
- soup = BeautifulSoup(page_text,'lxml')
- soup.tagName:定位标签(只可以定位到第一次出现的标签),返回的永远是一个单数
- soup.find(tagName,attrName="value"):基于属性定位实现的标签定位。返回的永远是一个单数
- soup.find_all():返回的永远是一个列表
- 取文本:
- string:取得标签中直系的文本内容
- text/get_text():取得的是标签下面所有的文本内容
- 取属性:tag['attrName']
- select:使用选择器定位标签。返回的是列表
- 标签,类,id选择器:select('选择器')
- 层级选择器:
- 单层级:'.tang > ul > li
- 多层级:'.tang li
案例:爬取三国演义整片小说内容
import requests
from bs4 import BeautifulSoup
#获取页面源码数据
url = ' http://www.shicimingju.com/book/sanguoyanyi.html'
headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36'
}
page_text = requests.get(url=url,headers=headers).text
#实例化soup对象
soup = BeautifulSoup(page_text,'lxml')
#解析出章节标题和详情页的链接
li_list = soup.select('.book-mulu > ul > li')
fp = open('./sanguo.txt','w',encoding='utf-8')
for li in li_list:
title = li.a.string
detail_url = 'http://www.shicimingju.com'+li.a['href']
#对详情页url发起请求,进行章节内容的解析提取
detail_page_text = requests.get(url=detail_url,headers=headers).text
#将详情页中的章节内容解析提取
detail_soup = BeautifulSoup(detail_page_text,'lxml')
div_tag = detail_soup.find('div',class_="chapter_content")
content = div_tag.text
fp.write(title+':'+content+'\n')
print(title,'下载存储成功!')
fp.close()
- 通用性比较强
- 环境的安装:pip install lxml
- 解析原理:
- 1.实例化一个etree对象,且将解析的页面源码加载到该对象中
- 2.使用该对象中的xpath方法结合着xpath表达式进行标签定位和数据解析提取
- etree对象的实例化:
- 本地加载:
tree = etree.parse('filePath')
- 网络加载:
tree = etree.HTML(page_text)
常用的xpath表达式:基于标签的层级实现定位. 返回的永远是一个列表
- /:从根标签开始实现层级定位
- //:从任意位置实现标签的定位
- 属性定位:tag[@attrName="attrValue"]
- 索引定位://div[@class="tang"]/ul/li[5] 索引值是从1开始
- 取文本:
- 取得直系文本内容:/text()
- 取得所有的文本内容://text()
- 取属性:/@attrName
案例:爬取58二手房的房源信息
from lxml import etree
import requests
headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36'
}
url = 'https://bj.58.com/shahe/ershoufang/?PGTID=0d30000c-0047-e8f5-0211-cc2e07b06314&ClickID=1'
page_text = requests.get(url=url,headers=headers).text
#数据解析(房屋的名称和价格)
tree = etree.HTML(page_text)
li_list = tree.xpath('//ul[@class="house-list-wrap"]/li')
all_data_list = []
for li in li_list:
name = li.xpath('./div[2]/h2/a/text()')[0]# ./表示的就是li标签
detail_url = li.xpath('./div[2]/h2/a/@href')[0]
if 'https:' not in detail_url:
detail_url = 'https:'+detail_url
price = li.xpath('./div[3]//text()')
price = ''.join(price)
# print(name,price,detail_url)
#获取详情页的页面源码数据,提取解析出房屋概况
detail_page_text = requests.get(url=detail_url,headers=headers).text
tree = etree.HTML(detail_page_text)
desc = tree.xpath('//div[@id="generalSituation"]//text()')
desc = ''.join(desc)
dic = {
'name':name,
'price':price,
'desc':desc
}
all_data_list.append(dic)
print(all_data_list,len(all_data_list)
案例:需求爬取当前页面全部的城市名称https://www.aqistudy.cn/historydata/
url = 'https://www.aqistudy.cn/historydata/'
page_text = requests.get(url=url,headers=headers).text
tree = etree.HTML(page_text)
#热门城市://div[@class="bottom"]/ul/li/a/text()
#全部城市://div[@class="bottom"]/ul/div[2]/li/a/text()
all_city_names = tree.xpath('//div[@class="bottom"]/ul/li/a/text() | //div[@class="bottom"]/ul/div[2]/li/a/text()')
print(all_city_names,len(all_city_names))
- 爬取基于某些用户的用户信息
- 使用流程:
- 注册
- 登陆:
- 普通用户:
- 查询剩余提分(充值)
- 开发者用户:
- 创建软件:我的软件-》添加新软件(ID,秘钥)
- 下载示例代码:开发文档-》点此下载:云打码接口DLL-》PythonHTTP示例下载
import http.client, mimetypes, urllib, json, time, requests
######################################################################
class YDMHttp:
apiurl = 'http://api.yundama.com/api.php'
username = ''
password = ''
appid = ''
appkey = ''
def __init__(self, username, password, appid, appkey):
self.username = username
self.password = password
self.appid = str(appid)
self.appkey = appkey
def request(self, fields, files=[]):
response = self.post_url(self.apiurl, fields, files)
response = json.loads(response)
return response
def balance(self):
data = {'method': 'balance', 'username': self.username, 'password': self.password, 'appid': self.appid, 'appkey': self.appkey}
response = self.request(data)
if (response):
if (response['ret'] and response['ret'] < 0):
return response['ret']
else:
return response['balance']
else:
return -9001
def login(self):
data = {'method': 'login', 'username': self.username, 'password': self.password, 'appid': self.appid, 'appkey': self.appkey}
response = self.request(data)
if (response):
if (response['ret'] and response['ret'] < 0):
return response['ret']
else:
return response['uid']
else:
return -9001
def upload(self, filename, codetype, timeout):
data = {'method': 'upload', 'username': self.username, 'password': self.password, 'appid': self.appid, 'appkey': self.appkey, 'codetype': str(codetype), 'timeout': str(timeout)}
file = {'file': filename}
response = self.request(data, file)
if (response):
if (response['ret'] and response['ret'] < 0):
return response['ret']
else:
return response['cid']
else:
return -9001
def result(self, cid):
data = {'method': 'result', 'username': self.username, 'password': self.password, 'appid': self.appid, 'appkey': self.appkey, 'cid': str(cid)}
response = self.request(data)
return response and response['text'] or ''
def decode(self, filename, codetype, timeout):
cid = self.upload(filename, codetype, timeout)
if (cid > 0):
for i in range(0, timeout):
result = self.result(cid)
if (result != ''):
return cid, result
else:
time.sleep(1)
return -3003, ''
else:
return cid, ''
def report(self, cid):
data = {'method': 'report', 'username': self.username, 'password': self.password, 'appid': self.appid, 'appkey': self.appkey, 'cid': str(cid), 'flag': '0'}
response = self.request(data)
if (response):
return response['ret']
else:
return -9001
def post_url(self, url, fields, files=[]):
for key in files:
files[key] = open(files[key], 'rb');
res = requests.post(url, files=files, data=fields)
return res.text
######################################################################
# 普通用户名
username = 'bobo328410948'
# 密码
password = 'bobo328410948'
# 软件ID,开发者分成必要参数。登录开发者后台【我的软件】获得!
appid = 6003
# 软件密钥,开发者分成必要参数。登录开发者后台【我的软件】获得!
appkey = '1f4b564483ae5c907a1d34f8e2f2776c'
# 图片文件
filename = 'getimage.jpg'
# 验证码类型,# 例:1004表示4位字母数字,不同类型收费不同。请准确填写,否则影响识别率。在此查询所有类型 http://www.yundama.com/price.html
codetype = 1004
# 超时时间,秒
timeout = 30
# 检查
if (username == 'username'):
print('请设置好相关参数再测试')
else:
# 初始化
yundama = YDMHttp(username, password, appid, appkey)
# 登陆云打码
uid = yundama.login();
print('uid: %s' % uid)
# 查询余额
balance = yundama.balance();
print('balance: %s' % balance)
# 开始识别,图片路径,验证码类型ID,超时时间(秒),识别结果
cid, result = yundama.decode(filename, codetype, timeout);
print('cid: %s, result: %s' % (cid, result))
###############################################
案例:人人网携带验证码的模拟登陆
import requests
from lxml import etree
from urllib import request
# from CodeClass import YDMHttp
#封装识别验证码图片的函数
def getCodeText(codeType,filePath):
result = None
# 普通用户名
username = 'bobo328410948'
# 密码
password = 'bobo328410948'
# 软件ID,开发者分成必要参数。登录开发者后台【我的软件】获得!
appid = 6003
# 软件密钥,开发者分成必要参数。登录开发者后台【我的软件】获得!
appkey = '1f4b564483ae5c907a1d34f8e2f2776c'
# 图片文件
filename = filePath
# 验证码类型,# 例:1004表示4位字母数字,不同类型收费不同。请准确填写,否则影响识别率。在此查询所有类型 http://www.yundama.com/price.html
codetype = codeType
# 超时时间,秒
timeout = 40
# 检查
if (username == 'username'):
print('请设置好相关参数再测试')
else:
# 初始化
yundama = YDMHttp(username, password, appid, appkey)
# 登陆云打码
uid = yundama.login();
print('uid: %s' % uid)
# 查询余额
balance = yundama.balance();
print('balance: %s' % balance)
# 开始识别,图片路径,验证码类型ID,超时时间(秒),识别结果
cid, result = yundama.decode(filename, codetype, timeout);
print('cid: %s, result: %s' % (cid, result))
return result
url = 'http://www.renren.com/SysHome.do'
headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36'
}
page_text = requests.get(url=url,headers=headers,proxies={'http':'116.228.233.90:8082'}).text
#解析出验证码图片的地址
tree = etree.HTML(page_text)
code_img_url = tree.xpath('//*[@id="verifyPic_login"]/@src')[0]
request.urlretrieve(url=code_img_url,filename='./code.jpg')
#使用打码平台识别验证码
code_text = getCodeText(2004,'./code.jpg')
# print(code_text)
#模拟登陆
login_url = 'http://www.renren.com/ajaxLogin/login?1=1&uniqueTimestamp=2019401113761'
data = {
"email": "www.zhangbowudi@qq.com",
"icode": code_text,
"origURL": "http://www.renren.com/home",
"domain": "renren.com",
"key_id": "1",
"captcha_type": "web_login",
"password": "17108719a8907d7a716631afc519561080a50ea31d92f64ae5f9ccd64b41e4b1",
"rkey": "465733ef9b05bd790ec81e9347025808",
"f": "http%3A%2F%2Fwww.renren.com%2F289676607",
}
#创建一个回话对象
session = requests.Session()
#产生cookie
response = session.post(url=login_url,headers=headers,data=data,proxies={'http':'119.180.135.210:8060'})
# print(response.status_code)
# page_text = response.text
# print(page_text)
#该次请求发送必须携带cookie
detail_url = 'http://www.renren.com/289676607/profile'
detail_page_text = session.get(url=detail_url,headers
- 快代理
- 西祠代理
- goubanjia
- 匿名度:
- 透明:对方服务器知道你使用了代理ip也知道你的真实ip
- 匿名:知道你使用了代理ip但是不知道你的真实ip
- 高匿:什么都不知道
- 类型:
- http:只可以发起http请求
- https:只可以发起https的请求
案例:简单代理池应用
http_list = [
{'http':'60.190.250.120:8080'},
{'http':'60.190.250.120:8080'},
{'http':'60.190.250.120:8080'}
]
https_list = [
{'https':'60.190.250.120:8080'},
{'https':'60.190.250.120:8080'},
{'https':'60.190.250.120:8080'}
]
url = 'http://www.baidu.com/s?wd=ip'
page_text = requests.get(url=url,headers=headers,proxies={'http':'60.190.250.120:8080'}).text
with open('./ip.html','w',encoding='utf-8') as fp:
fp.write(page_text)
import random
url = 'http://www.baidu.com/s?wd=ip'
response = requests.get(url=url,headers=headers,proxies=)
page_text = response.text
if response.url.split(':')[0] == 'http'
with open('./ip.html','w',encoding='utf-8') as fp:
fp.write(page_text)
- cookie:服务器端记录客户端的相关状态
- 处理cookie的方式:
- 手动处理:不建议
- 自动处理:回话对象Session,该对象可以像requests模块一样进行网络请求的发送(get,post)。session进行的请求发送可以自动携带和处理cookie。
案例:基于cookie的案例分析:https://xueqiu.com/
import requests
headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36'
}
#自动获取cookie,cookie就会自动存储到session中
session = requests.Session()
session.get('https://xueqiu.com/',headers=headers)
#捕获ajax数据包获取的url
url = 'https://xueqiu.com/v4/statuses/public_timeline_by_category.json?since_id=-1&max_id=-1&count=10&category=-1'
#携带cookie进行的请求发送
dic_json = session.get(url=url,headers=headers).json()
print(dic_json)
#从响应数据中获取详情页的url
# for dic in dic_json['list']:
# # print(dic)
# d = dic['data']
# detail_url = 'https://xueqiu.com'+d['target']
# print(detail_url
- 验证码处理:打码兔,云打码
- 模拟登陆:点击登陆按钮对应的post发起请求(参数的处理和携带)
- 爬取登陆后的先关的页面数据(模拟登陆后会产生cookie)
- 如何处理cookie:
- 手动:
- 自动:回话对象。
- 代理:
- 网站
- 匿名度:
- 类型:
- 代理应用在requests中
- get和post(参数):
- url
- headers
- data/prams
- proxies
- 多进程或者多线程(不建议)
- 线程池或者进程池(适当使用)
- 单线程+异步协程(推荐)
案例:实例化一个线程池提高爬虫效率
import requests
import re
from lxml import etree
from multiprocessing.dummy import Pool
import random
headers = {
'User-Agent':'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36'
}
def request_video(url):
return requests.get(url=url,headers=headers).content
def saveVideo(data):
name = str(random.randint(0,9999))+'.mp4'
with open(name,'wb') as fp:
fp.write(data)
print(name,'下载存储成功!!!')
url = 'https://www.pearvideo.com/category_1'
page_text = requests.get(url=url,headers=headers).text
tree = etree.HTML(page_text)
li_list = tree.xpath('//ul[@id="listvideoListUl"]/li')
#实例化一个线程池对象
pool = Pool(4)
video_url_list = [] #所有的视频连接
for li in li_list:
detail_url = 'https://www.pearvideo.com/'+li.xpath('./div/a/@href')[0]
detail_page_text = requests.get(url=detail_url,headers=headers).text
ex = 'srcUrl="(.*?)",vdoUrl='
video_url = re.findall(ex,detail_page_text,re.S)[0]
video_url_list.append(video_url)
#异步的获取4个视频的二进制数据
video_data_list = pool.map(request_video,video_url_list)
#进行视频的持久化存储
pool.map(saveVideo,video_data_list
- 概念:用来完成浏览器自动化相关的操作。可以通过代码的形式制定一些基于浏览器自动化的相关操作(行为动作),当代码执行后,浏览器就会自动触发先关的事件
- 环境安装:
- pip install selenium
- 下载对应浏览器的驱动程序
- 编码流程:
- 导包:from selenium import webdriver
- 实例化某一款浏览器对象
- 制定相关的行为动作
案例:执行js实现滚轮向下滑动
from selenium import webdriver
from time import sleep
bro = webdriver.Chrome(executable_path='./chromedriver.exe')
bro.get('https://xueqiu.com/')
sleep(5)
#执行js实现滚轮向下滑动
js = 'window.scrollTo(0,document.body.scrollHeight)' #向下滑动一屏高度,
bro.execute_script(js)
sleep(2)
bro.execute_script(js)
sleep(2)
bro.execute_script(js)
sleep(2)
bro.execute_script(js)
sleep(2)
a_tag = bro.find_element_by_xpath('//*[@id="app"]/div[3]/div/div[1]/div[2]/div[2]/a')
a_tag.click()
sleep(5)
#获取当前浏览器页面数据(动态)
print(bro.page_source)
bro.qui
案例:PhantomJs是一款无可视化界面的浏览器(免安装)
from selenium import webdriver
from time import sleep
bro = webdriver.PhantomJS(executable_path=r'C:\Users\Administrator\Desktop\爬虫+数据\爬虫day03\phantomjs-2.1.1-windows\bin\phantomjs.exe')
bro.get('https://xueqiu.com/')
sleep(2)
bro.save_screenshot('./1.png')
#执行js实现滚轮向下滑动
js = 'window.scrollTo(0,document.body.scrollHeight)'
bro.execute_script(js)
sleep(2)
bro.execute_script(js)
sleep(2)
bro.execute_script(js)
sleep(2)
bro.execute_script(js)
sleep(2)
bro.save_screenshot('./2.png')
# a_tag = bro.find_element_by_xpath('//*[@id="app"]/div[3]/div/div[1]/div[2]/div[2]/a')
# bro.save_screenshot('./2.png')
# a_tag.click()
sleep(2)
#获取当前浏览器页面数据(动态)
print(bro.page_source)
bro.quit(
案例:谷歌无头浏览器
from selenium import webdriver
from time import sleep
from selenium.webdriver.chrome.options import Options
# 创建一个参数对象,用来控制chrome以无界面模式打开
chrome_options = Options()
chrome_options.add_argument('--headless')
chrome_options.add_argument('--disable-gpu')
bro = webdriver.Chrome(executable_path='./chromedriver.exe',options=chrome_options)
bro.get('https://www.baidu.com')
sleep(2)
bro.save_screenshot('1.png')
#标签定位
tag_input = bro.find_element_by_id('kw')
tag_input.send_keys('人民币')
sleep(2)
btn = bro.find_element_by_id('su')
btn.click()
sleep(2)
print(bro.page_source)
bro.quit
案例:前进和后退
from selenium import webdriver
from time import sleep
bro = webdriver.Chrome(executable_path='./chromedriver.exe')
bro.get('https://www.baidu.com')
sleep(1)
bro.get('http://www.goubanjia.com/')
sleep(1)
bro.get('https://www.taobao.com')
sleep(1)
bro.back()
sleep(1)
bro.forward()
sleep(1)
print(bro.page_source)
bro.quit(
案例一:动作链
from selenium import webdriver
from time import sleep
from selenium.webdriver import ActionChains
bro = webdriver.Chrome(executable_path='./chromedriver.exe')
url = 'https://www.runoob.com/try/try.php?filename=jqueryui-api-droppable'
bro.get(url=url)
#如果定位的标签存在于iframe标签之中,则必须经过switch_to操作在进行标签定位
bro.switch_to.frame('iframeResult')
source_tag = bro.find_element_by_id('draggable')
#创建一个动作连的对象
action = ActionChains(bro)
action.click_and_hold(source_tag)
for i in range(4):
#perform表示开始执行动作链
action.move_by_offset(20,0).perform()
sleep(1)
bro.quit()
案例二:动作链
from selenium import webdriver
from time import sleep
from selenium.webdriver import ChromeOptions
from selenium.webdriver import ActionChains
option = ChromeOptions()
option.add_experimental_option('excludeSwitches', ['enable-automation'])
bro = webdriver.Chrome(executable_path='./chromedriver.exe',options=option)
url = 'https://www.runoob.com/try/try.php?filename=jqueryui-api-droppable'
bro.get(url=url)
#如果定位的标签存在于iframe标签之中,则必须经过switch_to操作在进行标签定位
bro.switch_to.frame('iframeResult')
source_tag = bro.find_element_by_id('draggable')
taget_tag = bro.find_element_by_id('droppable')
#创建一个动作连的对象
action = ActionChains(bro)
action.drag_and_drop(source_tag,taget_tag)
action.perform()
sleep(3)
# bro.quit()
- event_loop:事件循环,相当于一个无限循环,我们可以把一些函数注册到这个事件循环上,当满足某些条件的时候,函数就会被循环执行。程序是按照设定的顺序从头执行到尾,运行的次数也是完全按照设定。当在编写异步程序时,必然其中有部分程序的运行耗时是比较久的,需要先让出当前程序的控制权,让其在背后运行,让另一部分的程序先运行起来。当背后运行的程序完成后,也需要及时通知主程序已经完成任务可以进行下一步操作,但这个过程所需的时间是不确定的,需要主程序不断的监听状态,一旦收到了任务完成的消息,就开始进行下一步。loop就是这个持续不断的监视器。
- coroutine:中文翻译叫协程,在 Python 中常指代为协程对象类型,我们可以将协程对象注册到事件循环中,它会被事件循环调用。我们可以使用 async 关键字来定义一个方法,这个方法在调用时不会立即被执行,而是返回一个协程对象。
- task:任务,它是对协程对象的进一步封装,包含了任务的各个状态。
- future:代表将来执行或还没有执行的任务,实际上和 task 没有本质区别。
- 另外我们还需要了解 async/await 关键字,它是从 Python 3.5 才出现的,专门用于定义协程。其中,async 定义一个协程,await 用来挂起阻塞方法的执行。
案例:基本使用
import asyncio
#创建一个协程函数
async def hello(name):
print('hello to :',name)
#获取了一个协程对象
c = hello('bobo')
#创建一个事件循环对象
loop = asyncio.get_event_loop()
#将协程对象注册到事件循环中,然后启动事件循环对象
loop.run_until_complete(c)
案例:task的使用
import asyncio
async def hello(name):
print('hello to :',name)
c = hello('bobo')
loop = asyncio.get_event_loop()
#就协程进行进一步的封装,封装到了task对象中
task = loop.create_task(c)
print(task)
loop.run_until_complete(task)
print(task)
案例:future的使用
import asyncio
async def hello(name):
print('hello to :',name)
c = hello('bobo')
task = asyncio.ensure_future(c)
loop.run_until_complete(task)
案例:绑定回调(task)
def callback(task):
print('i am callback:',task.result())
import asyncio
async def hello(name):
print('hello to :',name)
return name
c = hello('bobo')
task = asyncio.ensure_future(c)
#给任务对象绑定一个回调函数
task.add_done_callback(callback)
loop.run_until_complete(task)
案例:多任务异步协程(假)
import asyncio
async def request(url):
print('正在下载:',url)
sleep(2) #非异步模块的代码:在此处如果存在非异步操作代码,则会彻底让asyncio失去异步的效果
print('下载成功:',url)
urls = [
'www.baidu.com',
'www.taobao.com',
'www.sogou.com'
]
start = time.time()
loop = asyncio.get_event_loop()
tasks = [] #任务列表,放置多个任务对象
for url in urls:
c = request(url)
task = asyncio.ensure_future(c)
tasks.append(task)
#将多个任务对象对应的列表注册到事件循环中
loop.run_until_complete(asyncio.wait(tasks))
print('总耗时:',time.time()-start)
案例:多任务异步协程(真)
import asyncio
async def request(url):
print('正在下载:',url)
# sleep(2) #非异步模块的代码:在此处如果存在非异步操作代码,则会彻底让asyncio失去异步的效果
await asyncio.sleep(2)
print('下载成功:',url)
urls = [
'www.baidu.com',
'www.taobao.com',
'www.sogou.com'
]
start = time.time()
loop = asyncio.get_event_loop()
tasks = [] #任务列表,放置多个任务对象
for url in urls:
c = request(url)
task = asyncio.ensure_future(c)
tasks.append(task)
#将多个任务对象对应的列表注册到事件循环中
loop.run_until_complete(asyncio.wait(tasks))
print('总耗时:',time.time()-start)
实例:多任务异步操作应用到爬虫中(假)
import requests
async def get_page(url):
print('正在下载:',url)
#之所以没有实现异步操作,原因是因为requests模块是一个非异步的模块
response = requests.get(url=url)
print('响应数据:',response.text)
print('下载成功:',url)
start = time.time()
urls = [
'http://127.0.0.1:5000/bobo',
'http://127.0.0.1:5000/jay',
'http://127.0.0.1:5000/tom'
]
tasks = []
loop = asyncio.get_event_loop()
for url in urls:
c = get_page(url)
task = asyncio.ensure_future(c)
tasks.append(task)
loop.run_until_complete(asyncio.wait(tasks))
print('总耗时:',time.time()-start)
实例:多任务异步操作应用到爬虫中(真)
支持异步的网络请求的模块:aiohttp
环境安装:pip install aiohttp
import aiohttp
import asyncio
async def get_page(url):
async with aiohttp.ClientSession() as session:
async with await session.get(url=url) as response:
page_text = await response.text() #read() json()
print(page_text)
start = time.time()
urls = [
'http://127.0.0.1:5000/bobo',
'http://127.0.0.1:5000/jay',
'http://127.0.0.1:5000/tom',
'http://127.0.0.1:5000/bobo',
'http://127.0.0.1:5000/jay',
'http://127.0.0.1:5000/tom',
'http://127.0.0.1:5000/bobo',
'http://127.0.0.1:5000/jay',
'http://127.0.0.1:5000/tom'
]
tasks = []
loop = asyncio.get_event_loop()
for url in urls:
c = get_page(url)
task = asyncio.ensure_future(c)
tasks.append(task)
loop.run_until_complete(asyncio.wait(tasks))
print('总耗时:',time.time()-start)
实例:如何实现数据解析---任务的绑定回调机制
import aiohttp
import asyncio
#回调函数:解析响应数据
def callback(task):
print('this is callback()')
#获取响应数据
page_text = task.result()
print('在回调函数中,实现数据解析')
async def get_page(url):
async with aiohttp.ClientSession() as session:
async with await session.get(url=url) as response:
page_text = await response.text() #read() json()
# print(page_text)
return page_text
start = time.time()
urls = [
'http://127.0.0.1:5000/bobo',
'http://127.0.0.1:5000/jay',
'http://127.0.0.1:5000/tom',
'http://127.0.0.1:5000/bobo',
'http://127.0.0.1:5000/jay',
'http://127.0.0.1:5000/tom',
'http://127.0.0.1:5000/bobo',
'http://127.0.0.1:5000/jay',
'http://127.0.0.1:5000/tom'
]
tasks = []
loop = asyncio.get_event_loop()
for url in urls:
c = get_page(url)
task = asyncio.ensure_future(c)
#给任务对象绑定回调函数用于解析响应数据
task.add_done_callback(callback)
tasks.append(task)
loop.run_until_complete(asyncio.wait(tasks))
print('总耗时:',time.time()-start)
- 概述什么是http协议
- 爬虫中常用头信息
- https中涉及到的三种加密方式
- requests模块的作用及编码流程
- requests如何进行参数封装,为什么要进行参数封装
- 简述目前接触到的反爬机制及其反反爬策略
- 什么是动态加载数据
- 爬虫的分类
- 通用爬虫:
- 聚焦爬虫:
- 增量式:
- 爬取图片的两种方式
- 使用requests
- urllib模块request中urlretrive
- 数据解析的基本原理
- 标签的定位
- 取文本或取属性
- xpath解析原理
- 实例化etree对象,且将源码加载到该对象中
- 使用xpath方法结合着xpath表达式进行标签定位和数据提取
- 属性定位[@attrName="value"]
- 索引定位:[1]
- / //
- 取文本: /text() //text()
- 取属性:/@attrName
- etree对象实例化的方式
- 本地加载:parse
- 网络加载:HTML
- bs4解析原理
- .tagName 单数
- find(属性定位) 单数 find('tagName',attrName="value")
- find_all 复数
- Beautiful对象实例化方式
- 面试题:如何爬取携带标签的指定页面内容
- 验证码识别
- 使用流程
- 开发者用户登陆:
- 创建一个软件
- 下载示例代码
- 模拟登录
- 实现流程(携带验证码):
- 对登陆页面进行请求,从请求到的页面源码中解析下载验证码图片
- 使用打码平台对验证码进行识别
- 基于登陆按钮发起一个post请求(处理参数)
- 意义or作用:获取cookie
- cookie处理
- 处理方式:
- 手动处理:不建议(通用性不强)
- 自动处理:回话对象。requests.Session()
- 代理操作
- 为什么使用代理
- 免费代理ip网站
- 匿名度
- 透明:
- 匿名:
- 高匿:
- 类型:
- http:
- https:
- requests如何应用代理
- proxies = {'http':'ip:port'}
- 代理池(列表):
- selenium
- 作用:可以让浏览器完成相关自动化的操作
- 和爬虫的关联:
- 模拟登陆
- 可以获取动态加载的页面数据
- 编码流程
- 导包
- 实例化浏览器对象(驱动)
- 制定相关自动化的行为动作
- 标签定位
- find系列的函数
- 节点交互
- click
- send_keys
- 执行js
- 获取页面源码数据
- page_source
- iframe包含标签定位:
- switch_to.frame(id)
- 规避selenium被检测
- 无头浏览器
- robots.txt
- UA检测
- 验证码
- cookie
- 检测ip
- 动态参数(token,key)
- 动态加载的数据
浙公网安备 33010602011771号