python-网络爬虫
基础网络知识
json(轻量级的数据交换格式。。没有带s的方法都是涉及到文件的操作)
一、json.dumps(i): 将特定格式的数据进行字符串化的操作
比如列表字典都可以进行字符串化操作然后写入json的file;而且如果是要写入json文件就必须要进行dumps操作;
二、json.dump():将数据转换成str格式,添加了将数据写入json文件的一个操作步骤
son.dump(data, file-open,ascii=False),可以包含三个属性,第三个ascii是用来避免出现unicode写入的乱码的;
三、json.loads():将字符型数据转换成原来的数据格式,诸如列表和字典
四、json.load():从json文件中读取数据,json.load(file-open)即可,这样可以还原在json文件中的原本的数据格式,诸如列表或者字典;file在open的时候最好是注意用encoding=‘utf-8’的编码,这样出来的数据就是原来的数据,而不会出现乱码;
URL(Uniform Resource Locator,统一资源定位符):网络地址
URL格式:protocol:// hostname[:port] /path/[;parameters] [?query]#fragment
中括号为可选选
第一部分是协议:http、https、ftp、file
第二部分是存放资源的服务器的域名系统或IP地址(有时候要包含端口号,各种传输协议都有默认的端口号,http默认为80)
第三部分是资源的具体位置(如目录或文件名)
网站检查
method(network-status右键显示method,再点击一次按钮类请求):
post(提交):向指定服务器提交被处理的数据
headers:
1)General:
远程地址(端口号)、请求地址(url),请求方法(post)
2)Request Headers:
通过User-Agent来判断是否是浏览器访问(或是代码访问)
3)From data(表单数据):post提交的主要内容
get(获取):是指服务器请求获得数据
隐藏(修改Headers)
1)通过Request的headers参数修改
2)通过Request.add_header(key,value)方法修改
一个请求修改User-Agent
初版隐藏:
#伪装 从User-Agent得知
header={"User-Agent":" Mozilla/5.0 (Windows NT 6.1; Win64; x64) "}
#封装
response=request.Request(url=base_url,headers=header,data=data_str)
#创建一个Request对象
req=request.urlopen(response).read().decode("utf-8")
#响应对象,read成网页内容,decode返回req字符串
网页爬取与代理
未解码版:
import urllib.request as r
response = r.urlopen('http://www.fishc.com')
response.read()
代理(用多个其他的服务器IP访问网页,并获取数据)
1.参数是一个字典{‘类型’,‘代理ip:端口号’}
键:代理类型(如http) 值:对应的IP
proxy_suppot = urllib.request.ProxyHandler({})
2.定制和创建一个opener
opener = urllib.request.build_opener(proxy_support)
平常的访问也是调用了opener,在这里我们定制一个opener,用代理ip去访问网页
3.安装opener(永久用代理) urllib.request.install_opener(opener)
4.调用opener(使用特殊的opener来打开网页)
opener.open(url)
初版代理:
import urllib.request as r
url='https://www.kuaidaili.com/free/'
proxy_support = r.ProxyHandler({'http':'58.22.177.200:9999'})
opener = r.build_opener(proxy_support)
r.install_opener(opener)
response = r.urlopen(url)
html = response.read().decode('utf-8')
print(html)
初版代理+隐藏
opener.addheaders[(key,value)]
例如:opener.addheaders[('User-Agent','*************')]
网页内容下载
图片下载初版:
import urllib.request as r
req =r.Request('http://placekitten.com/g/500/600')
response = r.urlopen(req)
cat_img = response.read()
with open('cat_500_600.jpg','wb') as f:
f.write(cat_img)
# fp=open(文件)等同于 with open(文件名) as fp
常用包、库
urllib包(url+lib,主要使用parse和request模块)
parse模块
urlencode():将字典转换为url格式
request模块
urlopen(url,)data=None):打开URL网址,返回响应对象(http.client.HTTPResponse对象)
url参数可以是一个字符串url或者是一个Request对象
data为None时用get获取,data赋值时为post提交
响应对象大概包括read()、readinto()、getheader()、getheaders()、fileno()、msg、version、status、reason、debuglevel和closed函数,
使用read()函数 返回未解码的网页内容(如字节流或图片)
read()得到内容后用decode()函数使用对应的解码方式,返回相应的对象(如utf-8 返回字符串)
geturl()、getcode()获取响应频率、info()
Request:信息更完善的请求对象,包括headers(请求头)等信息
request = urllib.request.Request(url = url,data = data, /
headers = headers,method = 'POST')
data参数要求bytes(字节流)类型,如果是一个字典,先用urllib.parse.urlencode()编码。
data为空,method默认为get。data不为空,method默认为post
data = urllib.parse.urlencode(字典).encode('utf-8')
requests模块(Python第三方库,处理URL资源更方便)
https://www.cnblogs.com/lei0213/p/6957508.html
requests是用python语言基于urllib编写的,采用的是Apache2 Licensed开源协议的HTTP库,requests比urllib更加方便
request支持HTTP连接保持和连接池,支持使用cookie保持会话,支持文件上传,支持自动响应内容的编码,支持国际化的URL和POST数据自动编码。
requests.get()
requests.get(url,params = None,headers = None,cookies = None,auth = None,timeout =无)
发送GET请求。 返回response对象。
参数:
url - 新的Request对象的URL。
params - (可选)使用请求发送的GET参数字典。(如需要的data数据)
头文件headers - (可选)使用请求发送的HTTP头文件字典。
如 : headers = { 'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) ' }
Cookie - (可选)使用请求发送的CookieJar对象。
auth - (可选)AuthObject启用基本HTTP身份验证。
超时 - (可选)描述请求超时的浮点数。
不带参数:requests.get(url)
带参数:requests.get(url=? params=字典 # 带参数的get请求
请求方式
requests.post("http://httpbin.org/post")
requests.put("http://httpbin.org/put")
requests.delete("http://httpbin.org/delete")
requests.head("http://httpbin.org/get")
requests.options("http://httpbin.org/get")
requests.post()
A:application/x-www-form-urlencoded ==最常见的post提交数据的方式,以form表单形式提交数据
url = 'http://httpbin.org/post'
data = {'key1':'value1','key2':'value2'}
r =requests.post(url,data)
B:application/json ==以json格式提交数据
url_json = 'http://httpbin.org/post'
data_json = json.dumps({'key1':'value1','key2':'value2'})
#dumps:将python对象解码为json数据
r_json = requests.post(url_json,data_json)
C:multipart/form-data ==一般使用来上传文件(较少用)
url = 'http://httpbin.org/post'
files = {'file':open('E://report.txt','rb')}
r = requests.post(url,files=files)
response模块(requests.response)
是requests.reponse 对象
打印response:<Response [200]>
request.content与request.text
response.text :返回的是一个 unicode 型的文本数据 (可能是str类型),通常需要转换为utf-8格式,否则就是乱码
response.enconding = "utf-8'
response.content :返回的是 bytes 型的二进制数据 (取图片,视频,文件),
直接写入不需要解码,想看的话需要decode成utf-8格式。
response.content.decode()
返回utf-8的字符串(可能是按照默认解码方式)
response是一个响应对象,post也有内容
response.json()
等同于json.loads(response.text)方法 (字符串转换成字典)
内在属性
cookie的一个作用就是可以用于模拟登陆,做会话维持
#打印请求页面的状态(状态码)
print(type(response.status_code),response.status_code)
#打印请求网址的headers所有信息
print(type(response.headers),response.headers)
#打印请求网址的cookies信息
print(type(response.cookies),response.cookies)
#打印请求网址的地址
print(type(response.url),response.url)
#打印请求的历史记录(以列表的形式显示)
print(type(response.history),response.history)
#解码方式
response.encoding
状态码200正常:
#如果response返回的状态码是非正常的就返回404错误
if response.status_code != requests.codes.ok:
print('404')
#如果页面返回的状态码是200,就打印下面的状态
response = requests.get('http://www.jianshu.com')
if response.status_code == 200:
print('200')
代理
1、设置普通代理
import requests
proxies = {
"http": "http://127.0.0.1:9743",
"https": "https://127.0.0.1:9743",
}
response = requests.get("https://www.taobao.com", proxies=proxies)
print(response.status_code)
2、设置用户名和密码代理
import requests
proxies = {
"http": "http://user:password@127.0.0.1:9743/",
}
response = requests.get("https://www.taobao.com", proxies=proxies)
print(response.status_code)
设置socks代理
安装socks模块 pip3 install ‘requests[socks]’
import requests
proxies = {
'http': 'socks5://127.0.0.1:9742',
'https': 'socks5://127.0.0.1:9742'
}
response = requests.get("https://www.taobao.com", proxies=proxies)
print(response.status_code)
超时设置、认证设置
超时设置:
通过timeout参数可以设置超时的时间
import requests
from requests.exceptions import ReadTimeout
try:
# 设置必须在500ms内收到响应,不然或抛出ReadTimeout异常
response = requests.get("http://httpbin.org/get", timeout=0.5)
print(response.status_code)
except ReadTimeout:
print('Timeout')
认证设置:
如果碰到需要认证的网站可以通过requests.auth模块实现
import requests
from requests.auth import HTTPBasicAuth
<br>#方法一
r = requests.get('http://120.27.34.24:9001', auth=HTTPBasicAuth('user', '123'))<br>
#方法二<br>r = requests.get('http://120.27.34.24:9001', auth=('user', '123'))
print(r.status_code)
证书
在请求https时,request会进行证书的验证,如果验证失败则会抛出异常
关闭证书验证:
import requests
# 关闭验证,但是仍然会报出证书警告
response = requests.get('https://www.12306.cn',verify=False)
print(response.status_code)
消除验证证书的警报:
from requests.packages import urllib3
import requests
urllib3.disable_warnings()
response = requests.get('https://www.12306.cn',verify=False)
print(response.status_code)
手动设置证书:
response = requests.get('https://www.12306.cn', cert=('/path/server.crt', '/path/key'))
print(response.status_code)
lxml库是Python的一个解析库,支持HTML和XML的解析,支持XPath。 lxml与xpath用于确定文档中某部分位置
安装,cmd下:pip install lxml
引入etree:from lxml import etree
将字符串等转换为html对象,并自动补全结点:html = etree.HTML(text)
读取文件为html对象:html = etree.parse('./test.html',etree.HTMLParser())
将html文件转为字符串并解码输出:
result = etree.tostring(html)
print(result.decode('UTF-8'))
XPath即为XML路径语言,它是一种用来确定XML/HTML文档中某部分位置的语言。
html对象就是xpath解析对象,返回一个列表
extract():
item['name'] = each.xpath("./a/text()").extract()[0]
each html文档
each.xpath("./a/text()") xpath解析返回的是一个选择器列表
extract() 转换为Unicode字符串列表
[0] 列表第一个位置
selenium 库:Web应用程序测试工具,Selenium测试直接运行在浏览器中,就像真正的用户在操作一样。
正则表达式(描述复杂规则的工具,re模块)
如想办法直接找到想要的数据(例如网页链接),而不是通过静态的前端标签
正则表达式以字符串的形式来描述
re模块
re.search(pattern, string, flags=0)
用于在字符串中搜索正则表达式模式 第一次出现的位置
也就是返回模式字符串在原始字符串中的第一个字符位置,没有返回None
pattern : 正则中的模式字符串(漠视规则)。r
模式字符串,转义python字符串,防止出错’`
string : 要被查找替换的原始字符串。
flags : 标志位,用于控制正则表达式的匹配方式,如:是否区分大小写,多行匹配等等。
正则表达式默认区分大小写模式(大小写敏感模式)
re.match()方法要求必须从字符串的开头进行匹配,如果字符串的开头不匹配,整个匹配就失败了;
元字符(具有特殊含义的字符)
'.'
:表示除了'\'
以外的任何字符
'\'
:转义正则表达式字符(普通变特殊,元字符变普通)
或引用序号对应的子组所匹配的字符串
'\数字'
:两种表示方案(根据数字的取值)
1)1-99:引用序号对应的子组所匹配的字符串
r'(fishC)\1' == r'fishCfishC' \1表示重复第一个子组的内容
2)0、三位数:8进制数(表示这个8进制数对应的ASCII码的字符)
如'\060' == '0'
因为060是‘0’的Ascii码的八进制形式
()
:子组(把一个东西当做整体),匹配圆括号中的正则表达式,或者指定一个子组的开始
注:子组的内容可以在匹配之后被 \数字 再次引用
'|'
:逻辑或
>>> re.search(r'fish(c|d)','fishc')
<re.Match object; span=(0, 5), match='fishc'>
>>> re.search(r'fish(c|d)','fishd')
<re.Match object; span=(0, 5), match='fishd'>
^
:(脱字符)匹配输入字符串的开始位置(模式串必须在字符串的开始位置)
如果设置了 re.MULTILINE 标志,^ 也匹配换行符之后的位置
$
:匹配输入字符串的结束位置
如果设置了 re.MULTILINE 标志,$ 也匹配换行符之前的位置
{min,max}
表示模式串匹配前面的子表达式(字符、子组)的次数(min-max)
>>> re.search(r'ab{3}c','abbbc')
<re.Match object; span=(0, 5), match='abbbc'>
#匹配3-10次
>>> re.search(r'ab{3,10}c','abbbbbbbc')
<re.Match object; span=(0, 9), match='abbbbbbbc'>
匹配1000以内的数字字符串
>>> re.search(r'\d{0,3}','188')
<re.Match object; span=(0, 3), match='188'>
1000以内的字符串匹配三次(***.***.***.***)
re.search(r'(([01]\d\d|2[0-4]\d|25[0-5])\.){3}([01]\d\d|2[0-4]\d|25[0-5])','192.168.1.1')
ip地址匹配
>>> re.search(r'(([01]{0,1}\d{0,1}\d|2[0-4]\d|25[0-5])\.){3}([01]{0,1}\d{0,1}\d|2[0-4]\d|25[0-5])','192.168.1.1')
<re.Match object; span=(0, 11), match='192.168.1.1'>
‘*’
:匹配前面的子表达式零次或多次,等价于 {0,}
'+'
:匹配前面的子表达式一次或多次,等价于 {1,}
'?'
:匹配前面的子表达式零次或一次,等价于 {0,1}
默认情况下 *、+ 和 ? 的匹配模式是贪婪模式(即会尽可能多地匹配符合规则的字符串);
*?, +?, ??
表示启用对应的非贪婪模式。
>>> re.search(r'.+','i love you')
<re.Match object; span=(0, 10), match='i love you'>
>>> re.search(r'.+?','i love you')
<re.Match object; span=(0, 1), match='i'>
[]
:字符类(字符集合),匹配字符类中的任何字符,返回匹配串 符合字符类中字符 的第一个位置
除了几个特殊字符,其他符号都当作普通字符来对待(如.
)
注1:连字符 - 如果出现在字符串中间表示字符范围描述;如果如果出现在首位则仅作为普通字符
注2:特殊字符仅有反斜线 \ 保持特殊含义,用于转义字符。其它特殊字符如 *、+、? 等均作为普通字符匹配
注3:脱字符 ^ 如果出现在首位则表示匹配 不包含在其中的任意字符(相当于取反);如果 ^ 出现在字符串中间就仅作为普通字符匹配
>>> re.search(r'[iloveILOVE]','ilove 123')
<re.Match object; span=(0, 1), match='i'>
>>> re.search(r'[a-z]','ilove 123')
<re.Match object; span=(0, 1), match='i'>
>>> re.search(r'[0-9]','ilove 123')
<re.Match object; span=(6, 7), match='1'>
如匹配0-255的数字字符串
该方法实际是匹配的第一个字符
>>> re.search(r'[0-255]','188')
<re.Match object; span=(0, 1), match='1'>
等同于
>>> re.search(r'[0-2]','188')
<re.Match object; span=(0, 1), match='1'>
该方法匹配三个字符类的字符串(0-300)
>>> re.search(r'[0-2][0-9][0-9]','188')
<re.Match object; span=(0, 3), match='188'>
该方法匹配0-255字符串(|表示或)
>>> re.search(r'[01]\d\d|2[0-4]\d|25[0-5]','188')
<re.Match object; span=(0, 3), match='188'>
匹配1000以内的数字字符串
>>> re.search(r'\d{0,3}','188')
<re.Match object; span=(0, 3), match='188'>
特殊字符(被'\'
转义的普通字符)
'\d'
表示匹配数字
>>> re.search(r'\d\d\d','ilove 123')
<re.Match object; span=(6, 9), match='123'>
re.findall():找到所有匹配的字符串并打包成列表返回
不只是找到第一个匹配的字符串然后返回
>>> re.findall(r'[a-z]','FIshc.com')
['s', 'h', 'c', 'c', 'o', 'm']
匹配规则为a-z,连续匹配到了六个字符串(特殊地,这里都是一个字符的字符串)
xpath:对HTML文档进行搜索
html对象就是xpath解析对象
xpath常用规则(返回list)
/用于获取直接子节点,//用于获取子孙节点:
表达式 描述
nodename 选择这个节点名的所有子节点
/ 从当前节点选择直接子节点
// 从当前节点选取子孙节点
. 选择当前节点
… 选取当前节点的父节点
@ 选取属性
引入:from lxml import etree
例子:
/html/head/title:选取html文档中<head>标签内的<title>元素
/html/head/title/text():选择上面提到的<title>元素的文字
//td:选择所有的<td>元素
//div[@class="mine"]:选取所有具有class=“”mine“”属性的div元素
获取所有节点:
result = html.xpath('//*')
'//'表示获取当前节点子孙节点,'*'表示所有节点,'//*'表示获取当前节点下所有节点
for item in result:
print(item)
获取所有特定节点,如获取所有的li节点。
result = html.xpath('//li')#将*改为li,表示只获取名称为li的子孙节点
#返回一个列表
for item in result:
print(item)
获取所有某特定节点下的子节点(被父结点包围),如li结点下的a结点
result = html.xpath('//li/a')#//li选择所有的li节点,/a选择li节点下的直接子节点a
for item in result:
print(item)
根据属性获取特定节点:
result = html.xpath('//li[@class="item-3"]')
#返回class属性为item-3的li结点(列表形式)
获取特定属性
html.xpath('//ul[@id="pins"]/li/a/@href')
#获取id为pins的ul结点 下的子节点li 下的子节点 的href属性的值
异常处理
URLError:访问网页异常
import urllib.request as r
import urllib.error
req=r.Request("http://www/ooxx-fishc.com")
try:
r.urlopen(req)
except urllib.error.URLError as e:
print(e.reason)
HTTPError:状态码异常
http状态码大全
400-499:问题来自于客户端
500-599:服务器问题
except urllib.error.HPPTError as e:
print(e.reason)