#============================爬虫准备工作============================
# 参考资料
# python网络数据采集, 图灵工业出版
# 精通Python爬虫框架Scrapy, 人民邮电出版社
# [Python3网络爬虫](http://blog.csdn.net/c406495762/article/details/72858983)
# [Scrapy官方教程](http://scrapy-chs.readthedocs.io/zh_CN/0.24/intro/tutorial.html)
# 前提知识
# url
# http协议
# web前端,html, css, js
# ajax
# re, xpath
# xml
#============================爬虫简介============================
# 爬虫定义:网络爬虫(又被称为网页蜘蛛,网络机器人,在FOAF社区中间,更经常的称为网页追逐者),
#是一种按照一定的规则,自动地抓取万维网信息的程序或者脚本。
#另外一些不常使用的名字还有蚂蚁、自动索引、模拟程序或者蠕虫。
# 两大特征
# 能按作者要求下载数据或者内容
# 能自动在网络上流窜
# 三大步骤:
# 下载网页
# 提取正确的信息
# 根据一定规则自动跳到另外的网页上执行上两步内容
# 爬虫分类
# 通用爬虫
# 专用爬虫(聚焦爬虫)
# Python网络包简介
# Python2.x:urllib, urllib2, urllib3, httplib, httplib2, requests
# Python3.x: urllib, urllib3, httplib2, requests
# python2: urllib和urllib2配合使用,或者requests
# Python3: urllib,requests
#==========================urllib=========================
# 包含模块
# urllib.request: 打开和读取urls
# urllib.error: 包含urllib.request产生的常见的错误,使用try捕捉
# urllib.parse: 包含解析url的方法
# urllib.robotparse: 解析robots.txt文件
# 案例v1:
from urllib import request
url = "http://jobs.zhaopin.com/..."
# 打开相应url并把相应页面作为返回
rsp = request.urlopen(url)
# 把返回结果读取出来
# 读取出来内容类型为bytes
html = rsp.read()
# 如果想把bytes内容转换成字符串,需要解码
html = html.decode("utf-8")
# 网页编码问题解决
# chardet 可以自动检测页面文件的编码格式,但是,可能有误
# 需要安装, conda install chardet
# 案例v2片段:
#利用 chardet自动检测
cs = chardet.detect(html)
# 使用get取值保证不会出错
html = html.decode(cs.get("encoding", "utf-8"))
# urlopen 的返回对象
# geturl: 返回请求对象的url
# info: 请求反馈对象的meta信息
# getcode:返回的http code
# request.data 的使用
# 访问网络的两种方法
# get:
# 利用参数给服务器传递信息,
# 参数为dict,然后用parse编码
# 案例v4片段:
from urllib import request, parse
url = 'http://www.baidu.com/s?'
wd = input("Input your keyword:")
# 要想使用data, 需要使用字典结构
qs = {"wd": wd}
# 转换url编码
qs = parse.urlencode(qs)
fullurl = url + qs
# 如果直接用可读的带参数的url,是不能访问的
#fullurl = 'http://www.baidu.com/s?wd=大熊猫'
rsp = request.urlopen(fullurl)
html = rsp.read()
# post
# 一般向服务器传递参数使用
# post是把信息自动加密处理
# 我们如果想使用post信息,需要用到data参数
# 使用post,意味着Http的请求头可能需要更改:
# Content-Type: application/x-www.form-urlencode
# Content-ength: 数据长度
# 简而言之,一旦更改请求方法,请注意其他请求头部信息相适应
# urllib.parse.urlencode可以将字符串自动转换成上面的
# 案例v5:经典案例:
'''
利用parse模块模拟post请求
分析百度词典
分析步骤:
1. 打开F12
2. 尝试输入单词girl,发现每敲一个字母后都有请求
3. 请求地址是 http://fanyi.baidu.com/sug
4. 利用NetWork-All-Hearders,查看,发现FormData的值是 kw:girl
5. 检查返回内容格式,发现返回的是json格式内容==>需要用到json包
'''
from urllib import request, parse
# 负责处理json格式的模块
import json
'''
大致流程是:
1. 利用data构造内容,然后urlopen打开
2. 返回一个json格式的结果
3. 结果就应该是girl的释义
'''
baseurl = 'http://fanyi.baidu.com/sug'
# 存放用来模拟form的数据一定是dict格式
data = {
# girl是翻译输入的英文内容,应该是由用户输入,此处使用硬编码
'kw': 'girl'
}
# 需要使用parse模块对data进行编码
data = parse.urlencode(data).encode("utf-8")
rsp = request.urlopen(baseurl, data=data)
json_data = rsp.read().decode('utf-8')
# 把json字符串转化成字典
json_data = json.loads(json_data)
print(type(json_data))
print(json_data)
for item in json_data['data']:
print(item['k'], "--", item['v'])
# 为了更多的设置请求信息,单纯的通过urlopen函数已经不太好用了
# 需要利用request.Request 类
# 构造一个Request的实例
# 我们需要构造一个请求头,请求头部应该至少包含传入的数据的长度
# request要求传入的请求头是一个dict格式
headers = {
# 因为使用post,至少应该包含content-length 字段
'Content-Length':len(data)
}
# 有了headers,data,url,就可以尝试发出请求了
req = request.Request(url=baseurl, data=data, headers=headers)
# 因为已经构造了一个Request的请求实例,则所有的请求信息都可以封装在Request实例中
rsp = request.urlopen(req)
# urllib.error
# URLError产生的原因:
# 没网
# 服务器链接失败
# 知不道制定服务器
# 是OSError的子类
# HTTPError, 是URLError的一个子类
# 案例v8
from urllib import request, error
try:
req = request.Request(url)
rsp = request.urlopen(req)
html = rsp.read().decode()
print(html)
except error.HTTPError as e:
print("HTTPError: {0}".format(e.reason))
print("HTTPError: {0}".format(e))
except error.URLError as e:
print("URLError: {0}".format(e.reason))
print("URLError: {0}".format(e))
except Exception as e:
print(e)
# 两者区别:
# HTTPError是对应的HTTP请求的返回码错误, 如果返回错误码是400以上的,则引发HTTPError
# URLError对应的一般是网络出现问题,包括url问题
# 关系区别: OSError-URLError-HTTPError
# UserAgent
# UserAgent: 用户代理,简称UA, 属于heads的一部分,服务器通过UA来判断访问者身份
# 常见的UA值,使用的时候可以直接复制粘贴,也可以用浏览器访问的时候抓包
1.Android
Mozilla/5.0 (Linux; Android 4.1.1; Nexus 7 Build/JRO03D) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166 Safari/535.19
Mozilla/5.0 (Linux; U; Android 4.0.4; en#gb; GT#I9300 Build/IMM76D) AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30
Mozilla/5.0 (Linux; U; Android 2.2; en#gb; GT#P1000 Build/FROYO) AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1
2.Firefox
Mozilla/5.0 (Windows NT 6.2; WOW64; rv:21.0) Gecko/20100101 Firefox/21.0
Mozilla/5.0 (Android; Mobile; rv:14.0) Gecko/14.0 Firefox/14.0
3.Google Chrome
Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.94 Safari/537.36
Mozilla/5.0 (Linux; Android 4.0.4; Galaxy Nexus Build/IMM76B) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.133 Mobile Safari/535.19
4.iOS
Mozilla/5.0 (iPad; CPU OS 5_0 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9A334 Safari/7534.48.3
Mozilla/5.0 (iPod; U; CPU like Mac OS X; en) AppleWebKit/420.1 (KHTML, like Gecko) Version/3.0 Mobile/3A101a Safari/419.3
# 设置UA可以通过两种方式:
# heads
# add_header
# 使用head方法伪装UA
# headers = {}
# headers['User-Agent'] = 'Mozilla/5.0 (iPad; CPU OS 5_0 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Version/5.1 Mobile/9A334 Safari/7534.48.3'
# req = request.Request( url, headers=headers)
# 使用add_header方法
req = request.Request(url)
req.add_header("User-Agent", "Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/27.0.1453.94 Safari/537.36")
# 正常访问
rsp = request.urlopen( req )
html = rsp.read().decode()
print(html)
# ProxyHandler处理(代理服务器)
# 使用代理IP,是爬虫的常用手段
# 获取代理服务器的地址:
# www.xicidaili.com
# www.goubanjia.com
# 代理用来隐藏真实访问中,代理也不允许频繁访问某一个固定网站,所以,代理一定要很多很多
# 基本使用步骤:
from urllib import request, error
url = "http://www.baidu.com"
# 使用代理步骤
# 1. 设置代理地址
proxy = {'http': '120.194.18.90:81' }
# 2. 创建ProxyHandler
proxy_handler = request.ProxyHandler(proxy)
# 3. 创建Opener
opener = request.build_opener(proxy_handler)
# 4. 安装Opener
request.install_opener(opener)
# 现在如果访问url,则使用代理服务器
try:
rsp = request.urlopen(url)
html = rsp.read().decode()
print(html)
except error.URLError as e:
print(e)
except Exception as e:
print(e)
# cookie & session
# 由于http协议的无记忆性,人们为了弥补这个缺憾,所采用的一个补充协议
# cookie是发放给用户(即http浏览器)的一段信息,session是保存在服务器上的对应的另一半信息,用来记录用户信息
# cookie和session的区别
# 存放位置不同
# cookie不安全
# session会保存在服务器上一定时间,会过期
# 单个cookie保存数据不超过4k, 很多浏览器限制一个站点最多保存20个
# session的存放位置
# 存在服务器端
# 一般情况,session是放在内存中或者数据库中
# 没有cookie登录,反馈网页为未登录状态
# 使用cookie登录
# 直接把cookie复制下来,然后手动放入请求头:
headers = {
"Cookie": "xxxx"
}
req = request.Request(url, headers=headers)
# http模块包含一些关于cookie的模块,通过他们我们可以自动使用cookie
# CookieJar
# 管理存储cookie,向传出的http请求添加cookie,
# cookie存储在内存中,CookieJar实例回收后cookie将消失
# FileCookieJar(filename, delayload=None, policy=None):
# 使用文件管理cookie
# filename是保存cookie的文件
# MozillaCookieJar(filename, delayload=None, policy=None):
# 创建与mozilla浏览器cookie.txt兼容的FileCookieJar实例
# LwpCookieJar(filename, delayload=None, policy=None):
# 创建与libwww-perl标准兼容的Set-Cookie3格式的FileCookieJar实例
# 他们的关系是: CookieJar-->FileCookieJar-->MozillaCookieJar & LwpCookieJar
# handler是Handler的实例
# 用来处理复杂请求
# 创立handler后,使用opener打开,打开后相应的业务由相应的hanlder处理
# cookie的保存-FileCookieJar
cookie.save(ignore_discard=True, ignore_expires=True)
# cookie的读取:
cookie.load('cookie.txt', ignore_discard=True, ignore_expires=True)
# 案例:利用cookiejar访问网站
# 自动使用cookie登录,大致流程是
# 打开登录页面后自动通过用户名密码登录
# 自动提取反馈回来的cookie
# 利用提取的cookie登录隐私页面
from urllib import request, parse
from http import cookiejar
# 创建cookiejar的实例
# cookie = cookiejar.CookieJar()
# 需要保存成文本时创建MozillaCookieJar或FileCookieJar的实例
filename = "cookie.txt"
cookie = cookiejar.MozillaCookieJar(filename)
# cookie的读取:
# cookie.load('cookie.txt', ignore_discard=True, ignore_expires=True)
# 生成 cookie的管理器
cookie_handler = request.HTTPCookieProcessor(cookie)
# 创建http请求管理器
http_handler = request.HTTPHandler()
# 生成https管理器
https_handler = request.HTTPSHandler()
# 创建请求管理器
opener = request.build_opener(http_handler, https_handler, cookie_handler)
def login():
'''
负责初次登录
需要输入用户名密码,用来获取登录cookie凭证
:return:
'''
# 此url需要从登录form的action属性中提取
url = "http://www.renren.com/PLogin.do"
# 此键值需要从登录form的两个对应input中提取name属性
data = {
"email": "13119144223",
"password": "123456"
}
# 把数据进行编码
data = parse.urlencode(data)
# 创建一个请求对象
req = request.Request(url, data=data.encode())
# 使用opener发起请求
rsp = opener.open(req)
# 保存cookie到文件
# ignor_discard表示即使cookie将要被丢弃也要保存下来
# ignore_expire表示如果该文件中cookie即使已经过期,保存
cookie.save(ignore_discard=True, ignore_expires=True)
def getHomePage():
url = "http://www.renren.com/965187997/profile"
# 如果已经执行了login函数,则opener自动已经包含相应的cookie值
rsp = opener.open(url)
html = rsp.read().decode()
if __name__ == '__main__':
login()
getHomePage()
# cookie作为一个变量,打印出来, 案例片段:
print(cookie)
for item in cookie:
print(type(item))
print(item)
for i in dir(item):
print(i)
# cookie的属性
# name: 名称
# value: 值
# domain:可以访问此cookie的域名
# path: 可以访问此cookie的页面路径
# expires:过期时间
# size: 大小
# Http字段
# SSL
# SSL证书就是指遵守SSL安全套阶层协议的服务器数字证书(SercureSocketLayer)
# 美国网景公司开发
# CA(CertifacateAuthority)是数字证书认证中心,是发放,管理,废除数字证书的收信人的第三方机构
# 遇到不信任的SSL证书,需要单独处理,案例:
# 导入pythopn ssl处理模块
import ssl
# 利用非认证上下文环境替换认证的向下文环境
ssl._create_default_https_context = ssl._create_unverified_context
url = "https://www.12306.cn/mormhweb/"
rsp = request.urlopen(url)
html = rsp.read().decode()
# js加密
# 有的反爬虫策略采用js对需要传输的数据进行加密处理(通常是取md5值)
# 经过加密,传输的就是密文,但是
# 加密函数或者过程一定是在浏览器完成,也就是一定会把代码(js代码)暴露给使用者
# 通过阅读加密算法,就可以模拟出加密过程,从而达到破解
# 过程参看案例v19
# 注意salt,sign的计算
# ajax
# 异步请求
# 一定会有url,请求方法,可能有数据
# 一般使用json格式
# 案例,爬去豆瓣电影, 案例v20
# 注意请求值
#================================Requests==========================
# HTTP for Humans,更简洁更友好
# 继承了urllib的所有特征
# 底层使用的是urllib3
# 开源地址: https://github.com/requests/requests
# 中文文档: http://docs.python#requests.org/zh_CN/latest/index.html
# 安装: conda install requests
# get请求
# requests.get(url)
# requests.request("get", url)
# 可以带有headers和parmas参数
import requests
url = "http://www.baidu.com"
# 两种请求方式
# 使用get请求
rsp = requests.get(url)
print(rsp.text)
# 使用request请求
rsp = requests.request("get", url, params=kw, headers=headers)
print(rsp.text)
# get返回内容
print(rsp.text)
print(rsp.content)
print(rsp.url)
print(rsp.encoding)
print(rsp.status_code) # 请求返回码
# post
rsp = requests.post(baseurl, data=data, headers=headers)
# date, headers要求dict类型,不需要编码成byte流
# proxy
#
proxies = {
"http":"address of proxy",
"https": "address of proxy"
}
rsp = requests.request("get", "http:xxxxxx", proxies=proxies)
# 代理有可能报错,如果使用人数多,考虑安全问题,可能会被强行关闭
# 用户验证
# 代理验证
#可能需要使用HTTP basic Auth, 可以这样
# 格式为 用户名:密码@代理地址:端口地址
proxy = { "http": "china:[email protected]:4444"}
rsp = requests.get("http://baidu.com", proxies=proxy)
# web客户端验证
# 如果遇到web客户端验证,需要添加auth=(用户名,密码)
autu=("test1", "123456")#授权信息
rsp = requests.get("http://www.baidu.com", auth=auth)
# cookie
# requests可以自动处理cookie信息
rsp = requests.get("http://xxxxxxxxxxx")
# 如果对方服务器给传送过来cookie信息,则可以通过反馈的cookie属性得到
# 返回一个cookiejar实例
cookiejar = rsp.cookies
#可以讲cookiejar转换成字典
cookiedict = requests.utils.dict_from_cookiejar(cookiejar)
# session
# 跟服务器端session不是一个东东
# 模拟一次会话,从客户端浏览器链接服务器开始,到客户端浏览器断开
# 能让我们跨请求时保持某些参数,比如在同一个session实例发出的 所有请求之间保持cookie
# 创建session对象,可以保持cookie值
ss = requests.session()
headers = {"User-Agent":"xxxxxxxxxxxxxxxxxx"}
data = {"name":"xxxxxxxxxxx"}
# 此时,由创建的session管理请求,负责发出请求,
ss.post("http://www.baidu.com", data=data, headers=headers)
rsp = ss.get("xxxxxxxxxxxx")
# https请求验证ssl证书
# 参数verify负责表示是否需要验证ssL证书,默认是True
# 如果不需要验证ssl证书,则设置成False表示关闭
# 如果用verify=True访问12306,会报错,因为他证书有问题
rsp = requests.get("https://www.baidu.com", verify=False)