不适合初学的,这个是小编的知识巩固杂记
1、AJAX
2、动态渲染页面
3、节点交互,点击、输入、清除;
动作链:from selenium.webdriver import ActionChains
4、执行JavaScript
5、获取节点信息
6、选项卡管理
7、Splash的使用
8、splash支持异步处理:
9、splash对象属性
10、splash对象的方法
splash api的调用:
11、splash负载均衡
12、selenium抓取淘宝商品
13、代理设置
selenium设置代理
15、APP的爬取
16、Charles的使用
17、APPium的基本使用
AJAX原理:Asynchronous JavaScript and XML,即异步的JavaScript和XML,利用JavaScript在保证页面不被刷新、页面不改变的情况下与服务器交换数据更新部分网页。
发送AJAX请求到网页更新步骤:发送请求、解析内容、渲染网页
发送请求的JavaScript代码:
var xmlhttp;
if (window.XMLHttpRequest) {
II code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp=new XMLHttpRequest();
} else {II code for IE6, IES
xmlhttp=new ActiveXObject (” Microsoft.XMLHTTP ”);
}
xmlhttp. onreadystatechange=function() {
if (xmlhttp.ready5tate == 4 && xmlhttp.status==200) {
document.getElementById(“myDiv”).innerHTML=xmlhttp.responseText;将di为myDiv的节点内部的HTML代码更改为服务器返回的内容
}
}
xmlhttp.open(“post”,“/ajax/”,true);
xmlhttp.send();这是JavaScript对ajax最底层的实现,实际上是新建了xmlhttprequest对象,然后调用onreadystatechange属性设置监听,然后调用post、send方法向某个链接发送请求。
AJAX其实有其特殊的请求类型,叫作xhr。实例中request headers中一个信息为:x-requested-with:xmlhttprequest此标记显示请求为ajax请求。
JavaScript动态渲染页面不只ajax一种。
模拟浏览器的库:selenium、splash、PyV8、Ghost等
selenium中获取单个节点的方法by_id、name、xpath、link_text、partial_link_text、tag_name、class_name、css_selector
find_element(By.ID,id);获取多个节点find_elements
source =browser.find_element_by_css selector('#draggable ' )
target= browser.find_element_by_css_selector('#droppable' )
actions = ActionChains(browser)
actions.drag_and_drop(source, target)
actions. perform()
使用execute_script()
browser. execute_script('window.scrollTo(o, document.body. scrollHeight )’)
browser. execute_script( 'ale rt (” To Bottom ”)')
获取属性get.attribute,比如class的获取:logo.get_attribute (’ class ' );获取文本值用text;获取id、位置、标签名、大小
切换frame:switch_to.frame切换
延时等待:隐式等待implicitly_wait;显式等待from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expec te d _c onditions as EC
browser = webdriver.Chrome()
browser.get (’ https://www.taobao.com /’)
wait = WebDriverWait(browser, 10)
input = wait. until(EC. presence_of _element_located( (By.ID ,’ q ’)))
可进行cookies添加、删除、获取
browser.execute_script (’ window.open ()’)
print( browser.window _handles)
browser.switch_to_window(browser.window_handles[l])
splash是一个JavaScript渲染服务,带有http api的轻量级浏览器。
可实现功能:异步方式处理多个网页渲染过程;获取渲染后的页面的源码或截图;通过关闭图片渲染或者使用adblock规则加快页面渲染速度;可执行特定JavaScript脚本;通过lua脚本来控制页面渲染过程;获取渲染的详细过程并通过har格式呈现。
splash执行整个网页渲染过程
function main(splash, args)
assert(splash:go(args. url) )
assert(splash:wait(o.s))
return {
html= splash :h tml(),
png = splash:png(),
har = splash: har(),
}
end通过lua语言脚本加载页面,最后返回网页源码、截图、har信息。
function main(splash, args)
local example_urls = {"url1","url2","url3"}
local urls = args . urls or example_urls
local results = {}
for index, url in ipairs(urls) do
local ok , reason = splash:go (” http ://” .. url )
if ok then
splash:wait(2)
results[url] = splash:png()
end
end
return results
end
main方法的第一个参数是splash,类似于selenium中的webdriver
args:可以获取加载时配置的参数,若为url,get请求,可以获得get请求参数,post同理。
function main(splash, args)
local url = args.url
end等价于 function main(splash)
local url=splash.args.url
end
js_enabled:这个属性是splash执行JavaScript的开关
function main(splash, args)
splash:go( ” url” )
splash. js _e nabled = false
local title = splash:evaljs (” document.title")
return {title=title}
end
resource_timeout:可以设置加载超时时间
images_enabled:设置图片是否加载,禁止图片可能会影响JavaScript渲染
plugins_enabled:控制浏览器插件是否开启
scroll_position:控制页面上下或左右浮动
function main(splash, args)
assert(splash:go('https://www.taobao.com ’))
splash.scroll_position = {y=400}
return {png=splash: png()}
end控制页面向下浮动400像素值
go:请求链接
ok, reason = splash:go{url, baseurl=nil, headers=nil, http_method=" GET", body=nil, formdata=nil}
wait:控制页面等待时间
ok, reason = splash:wait{time, cancel_on_redirect=false, cancel_on_error=true}
jsfunc:直接调用JavaScript定义的方法
function main( s p l a s h , args)
local get_div_count = splash : jsfunc([[
function () {
}
]])
var body = document.body;
var divs = body .getElementsByTagName (’ div');
return divs.length;
splash:go (” https://vrww.baidu. com ”)
return (” There are %s DIVs"):forma(
get_div _count())
end
evaljs:可以执行JavaScript代码并返回最后一条JavaScript语句的返回结果
result=splash:evaljs(js)
local title=splash:evaljs(“document.title”)
runjs:可以执行JavaScript代码
autoload:可以设置每个页面访问时候自动加载的对象
ok , reason = splash: au toload{source_or_url, source=nil, url=nil}
call_later:通过设置定时任务和延迟时间来实现任务延时执行
http_get:模拟发送http的get请求
response = sp lash:http_get{url, headers=nil, follow_re dir ects=true}
http_post:response = splash:http_post{url, h e a d e r s = 「 1 i l , follow_redirects=true, body=nil}
set_content:设置页面的内容;html:获取网页源码;png、jpeg获取网页截图har:获取页面加载过程描述;url:获取当前网页网址;get/add/clear_cookies:获取当前页面cookies;get/set_viewport_size获取/设置当前浏览器页面的大小;set_view_full:全屏显示;set_user_agent:设置浏览器头;set_custom_headers设置请求头。
select选择符合条件的第一个节点;select_all选择符合条件的所有节点;mouse_click模拟鼠标点击工作,传入的参数为x、y,也可直接选择某个节点;
render.html用于获取JavaScript渲染的页面的HTML代码
import requests
url = ’ http://localhost:8050/render.html?url=https://www.baidu.com&wait=5'增加等待时间
response = requests . get(url)
print(response.text)可以获得页面渲染后的源代码
render.png/jpeg示例:
import requests
url=“http : //localhost :80SO/render.png?url=https://www. taobao.com&wait=S&width=lOOO&height=700”
response = requests.get(url)
with open (’ taobao.p ng ’, t wb ’) as f:
f . write(response.content)
render.har获取页面加载的har数据
render.json此接口包含了前面接口的所有功能
http:/ /localhost:8050/render.json?url= htt ps: //htt pbin.org&html =l&har=l
execute最强大的接口,可实现交互操作
import requests
from urllib.parse import quote
lua='''
function main(splash)
return "hello"
end
'''lua脚本
url =’ http : //localhost:8050/execute?l ua_source =’+ quote(lua)
response = requests.get(url)
print(response.text)
import requests
from urllib.parse import quote
lua ='''
fuction main(splash, args)
local treat = require (” treat ”)
local response = splash:http_get(" http: // httpbin . org/get ”)
return {
html=treat.as_string(response.body),
url=response. url,
status=response.status
end
'''
url =’ http://localhost:80SO/execute?l ua _source=' + quote(lua)
response =requests.get(url)
print(response.text)
选用任意一台带有公网IP的主机来配置负载均衡,装好Nginx,修改nginx.cnf:
http{
up stream splash {
least_conn;
server 41.159. 27 . 223: 8050;
server 41.159. 27. 221: 8050;
server 41.159. 27. 9: 8050;
server 41. 159 .117. 119: 8050;
}
server {
listen 8050;
location I {
proxy_pass http: //s plash;
}
}
}
配置认证:splash是可以公开访问的,如果不让其公开访问,还可以配置认证,借助于Nginx,可以在server的location字段添加auth_basic和auth_basic_user_file
http{
up stream splash {
least_conn;
server 41.159. 27 . 223: 8050;
server 41.159. 27. 221: 8050;
server 41.159. 27. 9: 8050;
server 41. 159 .117. 119: 8050;
}
server {
listen 8050;
location I {
proxy_pass http: //s plash;
auth basic ” Restricted";
auth basic user_file /etc/nginx/conf . d/ .htpasswd;
}
}
}
这里使用的用户名、密码放在/etc/nginx/conf.d,用htpassword命令创建
wait.until(EC.presence_of_element_located((By.CSS_SELECTOR,'.m-itemlist.items.item')))
chorme headless模式:chorme59版本已经支持headless模式,无界面模式,这样爬取的时候就不会弹出浏览器了。
chrome_options = webdriver.ChromeOptions()
chrome_options .add_argument('--headless ’)
browser = webdriver.Chrome( chrome options=chrome _options)
proxy_handler = ProxyHandler({
’ http ’:’ http://' +proxy,
'https ’:’ https://' + proxy
})
socks5类型:
import socks
import socket
from urllib import request
from urllib.error import URLError
socks .set_default_proxy(socks.SOCKSS ,’ 127.0.0 .1 ’, 9742)
socket .socket = socks.socksocket
try:
response = request .urlopen (’ http: //httpb in.org /get ’)
print(response.read().decode('utf-8 ’))
except URLError as e:
print(e.reason)
from selenium import webdriver
proxy= 127.0.0.1:9743
chrome_ options = webdriver.ChromeOptions ()
chrome_options.add_argument ('--proxy-server=http ://’+ proxy)
browser = webdri ver.chorme(chorme_options=chorme_options)
browser.get (’ http://httpbin.org/get ' )
代理池维护:
' insert into %s (%s) values (%s )’% (table, keys, values)万能数据存储
requests中的Session可以帮助我们维持一个会话,而且可以自动处理cookies;访问登录页面获取初始的cookies,提取authenticity_token。
在没有登录的情况下,也可访问部分网页。
搭建cookies池需要一些账号,需要redis库,py中的redis-py、requests、selenium、flask
cookies架构:存储模块、生成模块、检测模块、接口模块
app的爬取相比web端爬取更加容易,反爬虫能力没有那么强,而且大多数以json形式传输的,解析更简单。
抓包软件:wireshark、filddler、charles、mitmproxy、anyproxy
确保手机和PC在同一个局域网内,可以使用手机模拟器通过虚拟网络连接,也可为真机。设置手机代理为Charles的代理地址,访问互联网的数据包就会经charles再转发到数据包真实的服务器,服务器返回的数据包由charles转发回手机,charles起到中间人的作用,所有流量包都可以捕捉到。
charles会一直监听PC和手机发生的网络数据包,捕获到的数据包都会显示在左侧。
一定要提前设置好charles的代理并配置好ca证书。
overview选项卡显示了请求接口的url,响应状态、请求方式等;
contents选项卡查看请求和响应的详细信息;
jsontext选项卡可查看response的body信息;
charles可以将捕获到的请求加以修改并发送修改后的请求
mitmproxy的使用
mitmproxy的功能:拦截http和https请求和响应;保存http会话并进行分析;模拟客户端发起请求,模拟服务器端返回响应;利用反向代理将流量转发给指定的服务器;利用py对http请求和响应进行实时处理。
mitmdump的使用
mitmdump是mitmproxy的命令行接口
命令启动mitmproxy:mitmdump -w outfile截获的数据会被保存在outfile文件中;mitmdump -s script.py这里指定当前处理脚本为script.py。
def request (flow) :
flow.request .headers['User-Agent ’] = 'MitmProxy ’
print(flow.request .headers)定义了一个request方法,参数为flow,其实是一个httpflow对象,通过request属性即可获取到当前请求对象。
mitmdump提供了专门的日志输出功能,可以设定不同级别以不同颜色输出结果。
from mitmproxy import ctx
def request(flow):
flow. request .headers [’ User-Agent']='Mitmproxy'
ctx.log.info(str(flow.request.headers))
ctx.log.warn(str(flow .r equest .headers))
ctx.log .error(str(fl ow.request.headers))
def request(flow):
request = flow.request
info = ctx . log.info
info(request.url)
info(str(reque st.headers))
info(str(reque st .cookie s))
info(reque st .ho st)
info(request.method)
info(str(request.port))
info(request.scheme)
修改请求的url:
from mitmproxy import ctx
def response(flow):
response = flow.response
info = ctx.log.info
mitmdump爬取“得到”app电子书信息
import json
from mitmproxy import ctx
def response(flow):
url =’ https://dedao.ig e tget.com/v3/di s cover/booklist ’
if flow.request.url.startswith(url) :
text=flow.response.text
data = json.loads(text)
books = data.get(' c ’ ) . get('list')
for book in books:
ctx.log.info(str(book))
appium是一个跨平台移动端自动化测试工具,可以便捷地为ios和Android平台创建自动化测试用例。可以模拟app内部的各种操作。
启动appium服务,将Android手机通过数据线和运行appium的pc相连,同时打开usb调试功能,确保爬虫可以连接到手机。
测试连接情况:adb devices -1
用appium内置的驱动器打开app,点击appium中的start new session,配置启动app时的desired capability参数
用py驱动app的方法:
首先需要在代码中指定一个appium server
server = ’ http: //localhost: 472 3/wd/hub ’
desired_caps={'platformName:'android',
'deviceName:'mi_note_pro',
'appPackage':'com.tencent.mm',
'appAcitivity':'.ui.LancherUI'}
新建一个session,类似点击appium内置驱动的start session按钮
from appi um import webdriver
from sele nium.webdriver. su pport.ui import WebDriverWait
driver = webdri ver.Remote (server , desired_ caps)配置完成后运行,就可以启动微信app
点击登录ell = driver. find_e lement_by_xpath (”/ hierarchy /an droid.widget.Framelayout/android.widget.Linearlayout/
android.widget.Framelayout/android.view.View/android . widget.Framelayout/android.widget . Linearlayout/
android.widget.Framelayout/android.widget . Relativelayout/android.widget .R el ative la yout/a ndro id.widget.
Button[l ]”)
ell . click()
wait = WebDriverWait(driver, 30)
login = wait . until(EC.presence_of_element_located((By.ID ,’ com .t encent . mm:id/cjk')))
log in.click()
phone = wait. until(EC. presence_of_element_ located( (By. ID, ' com. ten cent.mm:id/h2)))
phone.set_text('18888888888')
API:Appiumpythonclient
配置desired capability参数
首先需要在代码中指定一个appium server
from appium import webdriver
server = ’ http: //localhost: 472 3/wd/hub ’
desired_caps={'platformName:'android',
'deviceName:'mi_note_pro',
'appPackage':'com.tencent.mm',
'appAcitivity':'.ui.LancherUI'}
driver=webdriver.Rmote(server,desired_caps)
查找元素可以使用selenium来查找
el = driver.find_element_by_id (’ com .tencent.mm:id/cjk ’)
Android平台,可使用UIAutomator来进行元素选择
el = self .d river .find_element_by_android_uiautomator (’ new UiSe l ector() . description (” Animation ”)’)
els= sel f.dr iver.find_elements_by_android uiautomator('new UiSelector() .clickable(true)')
IOS平台上,可使用UIAutomation来进行元素选择
el = self.driver.find_element_by _ios _uiautomation(' . elements() [0] ’)
els= self.driver.find_element_by _ios _uiautomation( ' .elements ()’)
点击:可以使用tap方法,模拟手指点击,可设置按时长短
tap(self, positions, duration=None)
屏幕拖动:scroll(self,orgin_el,destination_el)
swipe()模拟从A滑动到B
swipe(self, start_x, start_y, end_x, end_y, duration=None)
flick方法模拟从A点快速滑动到B点:flick(self, start_x, start_y, end_x, end_y)
拖拽:drag_and_drop(self,orgin_el,destination_el)
文本输入:set_text
el = find_element_by_id (’ com.tencent.mm:id/cjk')
el.ste_text(‘hello’)
动作链:Touchaction支持tap、press、long_press、release、move_to、wait、cancel
el = self . driver.find_element_by_accessibility_id (’ Animation ' )
action = TouchAction(self .driver)
action.tap(el).perform()