1. 爬虫
[TOC]
1.1. 主要技术
基础技术栈 : requests + beautifulsoup + re
高级技术栈: scrapy框架
1.2. 爬虫基础知识
AJAX:Asynchronous JavaScript And XML。异步的javascript和xml,可以在不刷新网页的情况下更新网页的数据。
Cookies:也称为Cookie,是网站用于辨别用户身份、进行session跟踪而存储在用户本地终端上的数据。Cookie最典型的应用是判断用户是否已经登录网站、保留用户信息以简化登录手续。
request携带的是"Cookie",response携带的是"Set-Cookie"。
如果响应头的状态码为30?,代表重定向。浏览器会根据响应头中的Location字段,再次发送GET请求。
JSON:JavaScript Object Notation,是一种轻量级的数据交换格式,是一种格式化字符串。
json与python的list或dict相互转换:
import json
# json -> list/dict
json.loads('{"a":"123"}')
# list/dict -> json
json.dumps({'a':123}, indent=4) # indent添加缩进,使显示更美观
XHR:XMLHttpReques,Ajax相关的一个重要对象。
https中用到的算法:
- 非对称加密算法:RSA、DSA/DSS
- 对称加密算法:AES、RC4、3DES
- Hash算法:MD5、SHA1、SHA256
robots.txt:Robots Exclusion Standard,网络爬虫排除标准,网站告知网络爬虫哪些页面可以抓取,哪些不行。放在网站根目录下。
Cookie不能添加到请求头Headers中,不然只能在几个页面中得到数据,不是真正的登陆。
每个domain最多只有20条cookie,且每个cookie长度不超过4kB,否则会被截断。
数据来源:大部分数据来源于Doc、XHR、JS标签。
Requests的GET和POST方法的请求参数分别是params和data。
如果解码出错,可以使用errors选项忽略掉:
# xx是一个bytes
xx.decode(encoding=response.encoding, errors='ignore')
不分析url,直接爬取手机上的数据:使用UiAutomator操作Android手机(需要安装Android SDK、JRE),然后使用python来操作UI Automator,从而控制手机。将手机上的内容转换成xml形式,然后进行抓取。
模拟人操作手机屏幕的任何行为,并直接读取屏幕上的文字。
需要安装第三方库:
pip install uiautomator
注:UI Automator Viewer与python uiautomator 不能同时使用。
1.3. 反爬虫技术及应对手段
- 用户请求的Headers:对Headers的User-Agent进行检测,或者对Referer进行检测(一些资源网站的防盗链就是检测Referer)
- 用户操作网络行为:通过检测用户行为来判断用户行为是否合规。
- 同一IP短时间多次访问同一页面:使用IP代理,可以在IP代理平台上通过API接口获得,每请求几次就更换一个IP。
- 同一账户短时间内多次进行相同操作:每次请求间隔几秒后再发送下一个请求,可以在代码中加一个延时功能。
- 网站目录数据加载方式(采用异步加载):针对Ajax请求,分析具体的请求参数和响应的数据结构及其含义,在爬虫中直接模拟Ajax请求。
- 数据加密:某些网站可能对Ajax的请求参数进行加密
- 加密代码一般是使用javascript实现的,可以自行分析加密方式。
- 使用Selenium+chromedriver(自动化测试技术),调用浏览器内核,利用Selenium模拟人为操作网页,并触发网页中的js脚本。
- 验证码识别:通过第三方平台处理,或OCR技术识别。
1.4. 动态网页爬取
主要内容:抓取动态网页,执行相关的javascript代码,使用鼠标进行点击等
技术选择:
- selenium:适合用来加载动态页面,进行比较复杂的登陆操作(各种类型的验证码)。
- splash:用于加载动态页面(执行js)。
1.4.1. selenium:模拟浏览器
selenium是一个网页自动化测试工具,可以通过代码来操作网页上的各个元素。
python使用:
pip install selenium
下载浏览器驱动程序:
- Chrome:http://chromedriver.chromium.org/downloads(这个需要vpn),http://chromedriver.storage.googleapis.com/index.html 。
- Firefox:
- PhantomJS:https://phantomjs.org/download.html。
PhantomJS是没有无界面的,其他的2个有界面(也可以使用headless参数屏蔽页面)。
注:驱动要和本机上装的相应浏览器的版本保持一致,不然会出错。
chromedriver/firfoxdriver
from selenium import webdriver
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions
chrome = webdriver.Chrome(executable_path=chrome_path) # chrome_path指定驱动路径
chrome.get(login_url)
WebDriverWait(chrome, 5).until(
expected_conditions.title_is('登录 - 新浪微博'), '加载登陆页面失败'
)
? scrapy程序采用中间件MobilesDownloaderMiddleware实现Chrome浏览器的嵌入,当一个Request申请时,如果不是图片申请就使用Chrome浏览器获取网页的Response,以保证js的执行。否则直接使用默认方法得到response。
1.4.2. Splash:爬取动态页面
splash文档:https://splash.readthedocs.io/en/latest/index.html
github地址:https://github.com/scrapy-plugins/scrapy-splash
splash是一个JavaScript渲染引擎。使用WebKit开发的轻量级无界面浏览器,提供基于HTTP接口的JavaScript渲染服务。
splash安装
在linux上,使用docker运行splash:
docker pull scrapinghub/splash
docker run -p 8050:8050 -p 5023:5023 scrapinghub/splash
docker run -p 8050:8050 scrapinghub/splash
使用requests进行测试:
import requests
from scrapy.selector import Selector
host = 1.1.1.1 # 你docker(或splash)的安装地址
splash_url = 'http://' + host +' :8050/render.html'
args = {'url':'http://quotes.toscrape.com/js','timeout':10,'image':0}
response = requests.get(splash_url,params = args)
sel = Selector(response)
sel.css('div.quote span.text::text').extract()
最后输出不为空,则说明安装成功。
splash服务:
- render.html:提供JavaScript页面渲染服务。
- execute:执行用户自定义的渲染脚本(lua),利用该端点可以在页面中执行JavaScript代码。
render.html
服务端点 | render.html |
---|---|
请求地址 | http://localhost:8050/render.html |
请求方式 | GET/POST |
返回类型 | html |
常用参数:
args = {
'url':'http://quotes.toscrape.com/js', # 需要渲染的js页面,必选
'timeout':10, # 渲染页面超时时间,float
'wait':2, # 等待页面渲染的时间,float
'proxy':'http://u:passwd@host:port', # 代理服务器地址
'image':0, # 0为不下载图片,1为下载图片(默认)
'js_source':'', # 用户自定义的js代码,在页面渲染前执行
}
execute端点
可以将execute端点的服务看做一个可用lua语言编程的浏览器,功能类似PhantomJS。使用lua脚本来模拟浏览器行为。
服务端点 | execute |
---|---|
请求地址 | http://localhost:8050/execute |
请求方式 | POST |
返回类型 | 自定义 |
常用参数:
args = {
'lua_source':'xxxx', # 用户自定义的lua脚本,必选
'timeout':10, # 渲染页面超时时间,float
'proxy':'http://u:passwd@host:port', # 代理服务器地址
}
lua脚本必须包含一个main函数作为程序入口,main函数会传入一个splash对象(lua中的对象),用户可以调用该对象的方法来操作splash。
lua函数:
function main(splash)
splash:go("http://example.com") -- 打开页面
splash:wait(0.5) -- 等待加载
local title = splash:evaljs("document.title") -- 执行js代码
return {title=title} -- 返回lua中的表,会被编码成json串。
end
常用函数:
- splash:url():返回当前页面的url。
- splash:html():返回当前页面的html文本。
- splash:get_cookies():获取全部Cookie信息。
在scrapy中使用splash
首先需要安装scrapy-splash:
pip install scrapy-splash
相关配置:
# setting.py
SPLASH_URL = 'http://127.0.0.1:8050/'
# 开启下载中间件,并调整HttpCompressionMiddleware的次序
DOWNLOADER_MIDDLEWARES = {
# Engine side
'scrapy_splash.SplashCookiesMiddleware': 723,
'scrapy_splash.SplashMiddleware': 725,
'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware': 810,
# Downloader side
}
# 去重过滤器
DUPEFILTER_CLASS = 'scrapy_splash.SplashAwareDupeFilter'
# 支持cache_args(可选)
SPIDER_MIDDLEWARES = {
'scrapy_splash.SplashDeduplicateArgsMiddleware': 100,
}
HTTPCACHE_STORAGE = 'scrapy_splash.SplashAwareFSCacheStorage'
在scrapy_splash中有一个SplashRequest类,用户只需使用SplashRequst来替代Request发送请求。
在爬虫中调用:
from scrapy_splash import SplashRequst
yield SplashRequest(url,self.parse,endpoint='render.html',
args={}
)
1.5. 模拟登陆
1.5.1. 添加cookies
1. 从浏览器中复制请求头
在登陆某网站后,复制该页面的Request中Headers的Cookie。将其添加到请求头中。
有一种方法,直接copy请求头,然后将其附着到session上,这样只能访问你copy的那个网页,cookies并不会真正的被设置。
2. 使用browser_cookie3从浏览器中获得cookie
python库browser_cookie3可以获取chrome或firefox浏览器中的Cookie。
import browser_cookie3
# 返回http.cookiejar.CookieJar
browser_cookie3.chrome(domain_name=domain)
获取一个已经登录网站的cookie:
import requests
import browser_cookie3
# 返回一个 requests.cookies.RequestsCookieJar
def get_cookiejar_from_browser(domain):
cj = browser_cookie3.chrome(domain_name=domain)
cookiejar = requests.cookies.RequestsCookieJar()
for c in cj:
cookiejar.set(c.name, c.value, domain=c.domain, path=c.path)
return cookiejar
1.5.2. 模拟表单登陆
适合没有或只有简单验证手段的网站。如简单的数字验证码,可以调用ocr模块进行识别。
表单中可能会有隐藏项。
可以安装loginform来快速构建表单数据。
from loginform import fill_login_form
formdata, login_url, method = fill_login_form(login_url, response.text, user, passwd)
fill_login_form 返回包含3个元素的元组,分别是所有表单项组成的列表(每隔表单项是一个(x,y)类型的元组),登陆提交表单的地址,提交表单的方法。
OCR识别验证码
使用orc识别验证码,需要现在对应电脑上安装orc软件。
from PIL import Image # PIL通过pip install pillow安装
import pytesseract
from io import BytesIO
img = Image.open('code.png')
# img = Image.open(BytesIO(response.body)) # 使用ByteIO(bytes)转换
img = img.convert('L') # 转换为黑白图
res = pytesseract.image_to_string(img)
img.close()
网络平台识别验证码
可以在阿里云市场找到验证码识别平台。购买,调用相关接口,获取识别结果。
人工识别验证码
将验证码图片显示出来,然后人工输入验证码。
1.5.3. 使用selenium模拟登陆
适用于验证码比较复杂的。