爬虫
爬虫也叫网络蜘蛛,网络机器人.是一个自动下载网页的计算机程序或自动化脚本.网络爬虫像蜘蛛一样
在网络上爬行.它以一个称为种子集的URl集合为起点,沿着URl的丝线爬行.下载每一个URL所指向的网页,
分析网页,提前新URl,记录已经爬过的内容,循环往复,直到URL队列空或者满足条件.达到遍历URL的目的
python爬虫技术
爬虫原理
分为四种: 通用 聚焦 增量式 深沉
通用
由一批种子 爬取整个网络 采用深度优先 广度优先
聚焦
又叫主题网络爬虫
只选择性[爬取与预设主题相关的页面
四种:
基于内容评价
--将用户输入作为主题 爬取含有查询词的页面 但不知道有无关系
基于链接结构
--PageRank 爬取重要的页面
基于增强学习
--将增强学习引入爬虫 利用贝叶斯分类器对网页进行分类 计算重要性 进行排序
基于语境图
--构建语境图来学习网页间相关度 计算当前页面到相关页面的距离,距离近的优先
增量
只对已经下载的进行增量式更新,或只爬取新产生或者发生变化的网页
可以保证爬取页面的新
三种:
统一更新法
--相同频率访问所有的网页
个体更新法,,,,
--根据个体网页的改变频率决定访问频率
分类更新法
--将网页分为快网页 慢网页 分别设置不同的频率
深层
web页面分为深层和浅层
浅层可以搜索到
深沉不可以搜索到 隐藏在表单后 如登录后才能进入的网页
爬虫合法性
明确注意
1. 个人隐私数据不可爬
2. 明确禁止的数据不可爬 如密码等
3. 注意版权问题 作者授权过的 不可以爬取后用于商业用途
robot.txt协议
爬虫爬取数据 需要遵守网站拥有者针对爬虫制定的协议 robot.txt
认识反爬虫
网站所有者 把所有的网站访问者中识别爬虫并进行响应处理 (通常为禁用IP)的过程 叫做反爬虫
爬虫会消耗大量的服务器资源 增加运行压力
通过User-Agent校验反爬
浏览器发送请求时 会附带一部分的浏览器及当前系统环境的参数给服务器,
这部分被放在HTTP请求得Hearders部分
服务器会通过 User-Agent值来区别不同的浏览器
通过访问频度反爬
普通用户通过浏览器访问网页比爬虫慢得多 所以网站会对访问频率设置阈值来进行反爬
通过验证码反爬
有部分网站 必须要输入验证码才能继续操作
通过变换网页结构反爬
更换网页结构,使爬虫无法解析网页结构
通过账号权限反爬
有部分网站需要登录才可以继续操作
如何针对反爬虫
发送模拟User-Agent
发送模拟User-Agent来通过服务器的检验
调整访问频率
通过调整访问频率来确保不会被限制
通过验证码校验
可以通过更换IP或者使用IP代理 来反爬虫 对于验证码只能通过算法或使用Cookie绕过验证码
对网站结构变化
1.在变化前全部爬取
2.使用脚本对网站结构监测 当变化 就停止爬虫
通过模拟登录
通过代理IP
爬虫环境配置
python库
通用
1. urllib 提供了对url的操作的功能
2. Requests 基于1 采用开源协议的HTTP库
3. urllib3 提供了标准库内没有的特性 线程安全,链接池等
框架
Scrapy 一个为爬取网站数据 提取结构性数据编写的应用框架
HTML/XML解析器
lxml C编写的高效库
Beautiful Soup4 纯python编写 效率低
安装mysql数据库
安装MongoDB数据库
静态网页爬取
静态网页是网站建设的基础 通常为纯粹的HTMl格式 也可以包含
一部分的动画 如GIF Flash 滚动字幕等 这些网页的扩展名为.htm,.html
利用urllib3 和 requests 获取网页
关于urllib3 request的配置
点击查看urllib3
import urllib3
# 在这里设置全局的 同下
http = urllib3.PoolManager()
url = "http://www.tipdm.com/tipdm/index.html"
# rq = http.request("GET",url)
# # 返回状态响应码
# print(rq.status)
# # 返回响应实体
# print(rq.data)
# 请求头处理
# 对于 request() 函数 需要传入headers参数 可以通过定义字典实现
# User-Agent信息包含了 使用的浏览器 和 使用的系统
ua = {"User-Agent":"Mozilla/5.0 (Windows NT 6.1; Win64; x64) Chrome/65.0.3325.181"}
# rq = http.request("GET",url,ua)
# print(rq.data)
# timeout设置
# 可以防止由于服务器或者网络问题造成的丢包 可以在GET请求中 加入timeout参数 通常为浮点数 根据需求的不同
# timeout参数提供了多种设置方法
# 可以设置 全部的timeout参 也可以 分别设置 连接和读取的timeout参
# 在PoolManager实例中 可以设置应用全局的 timeout参数
# 设置都为3
rq = http.request("GET",url,timeout = 3.0)
print(rq.data)
# 分别设置为 连接1 读取3
rq = http.request("GET",url,timeout=urllib3.Timeout(connect=1.0,read=3.0))
print(rq.data)
# 在这里设置全局的 同下
# http = urllib3.PoolManager(timeout = 3.0)
# http = urllib3.PoolManager(timeout = urllib3.Timeout(connect = 1.0,read = 3.0))
# 请求重试
# urllib3 库可以通过 设置request函数的retries参 进行重试控制 默认进行3次重试 以及3次重定向
# 统一设置
# http = urllib3.PoolManager(timeout = 3.0,retries = 10)
# http = urllib3.PoolManager(timeout = urllib3.Retry(5,read=4))
# rq = http.request("GET",url,timeout = 3.0,retries = 5)
# 分别定义重定向 和 重试
# rq = http.request("GET",url,timeout = 3.0,retries = 5,redirect = 4)
# 关闭
# rq = http.request("GET",url,timeout = 3.0,retries = False)
# 仅关闭重定向
# rq = http.request("GET",url,timeout = 3.0,redirect = False)
点击查看代码
import urllib3
# 建立链接池
http = urllib3.PoolManager()
# 设置请求网站
url = "http://www.tipdm.com/tipdm/index.html"
# 定义请求头
# google浏览器 windos操作系统
ua = {"User-Agent":"Mozilla/5.0 (Windows NT 6.1; Win64; x64) Chrome/65.0.3325.181"}
tm = urllib3.Timeout(connect=1.0,read=4.0)
rq = http.request("GET",url,headers=ua,timeout=tm,retries=5,redirect=4)
print("状态码:",rq.status)
print("返回主体:",rq.data)
-----------------------------------------------------
关于requests库实现访问网页
# requests 是一个原生的 http库 比 urllib3 更容易使用
# 相对于urllib3 requests库 可以发送HTTP/1.1请求
# 无须手动为url添加查询字串 也不需要对POST数据进行编码
import chardet
import requests
url = "http://www.tipdm.com/tipdm/index.html"
requests.get(url,**kwargs)
# 仅一行 就可以完成GET请求
res = requests.get(url)
print("状态码:",res.status_code)
print("编码类型:",res.encoding)
print("响应头:",res.headers)
print("网页内容:",res.text)
# 可以手动的更改结果的编码
# res.encoding = "utf-8"
# 但是手动的更改编码无法适应全部的网页
# 所以 可以使用 chardet库 来检测给定的字符串的编码 chardet.detect(byte_str)
# content内是 byte 类型的原始内容
print(chardet.detect(res.content))
ua = {"User-Agent":"Mozilla/5.0 (Windows NT 6.1; Win64; x64) Chrome/65.0.3325.181"}
# 给requests.get() 添加请求头
res = requests.get(url,headers=ua)
print("响应头:",res.headers)
# Timeout设置
res = requests.get(url,headers=ua,timeout=2)
print("响应头:",res.headers)
完整的requests的get请求
点击查看requests
import chardet
import requests
url = "http://www.tipdm.com/tipdm/index.html"
ua = {"User-Agent":"Mozilla/5.0 (Windows NT 6.1; Win64; x64) Chrome/65.0.3325.181"}
# 给requests.get() 添加请求头
res = requests.get(url,headers=ua,timeout = 2)
print("响应码:",res.status_code)
# 是在本电脑的编码
print("当前页面的编码:",res.encoding)
# 修改当前页面的编码为 页面本来的编码
res.encoding = chardet.detect(res.content)['encoding']
print("修改后的编码:",res.encoding)
print("响应头:",res.headers)
print("页面内容:",res.text)
解析网页
对网页的解析可以获得网页包含的数据信息 如文本 图片 视频 等
学会使用 Chrome开发者工具查看页面信息
学会正则表达式匹配字符串
学会正则表达式查找页面内容
学会lxml库的etree模块实现获得网页
使用Beautiful Soup4 遍历文档树
Chrome开发者工具
源代码: 可设置调试js
网络: 可以查看页面请求 下载 文件 查看HTTP请求头 响应内容
性能: 展示页面加载花费时间
内存: 提供比性能更详细分析
应用: 检测加载的所有资源
安全: 调试页面安全 认证问题
对于爬虫 我们常常使用 元素面板 源代码面板 网络面板
使用正则表达式解析网页s
python的正则表达式模块 re
re内的函数:
1. compile 将正则字符串转为 Patter匹配对象
2. match 将输入字符串重头进行匹配 如果无 或者 到达尾部 就返回None 否则获得结果
3. search 对输入进行扫描 对正则进行匹配 获得结果 没有返回None
一个是重头开始 一个是整体开始
4. split 将能够匹配的字符串作为分隔符 分割后返回一个列表
5. findall 搜索整个字符串 返回一个包含全部可匹配子串的列表
6. finditer 返回迭代器
7. sub 替换匹配的子串内容
re模块解析html代码
import re
import requests
import chardet
# 将正则表达式 转化内对象 pattern str类型 flags str类型 |可同时生效
# flags : re.I 忽略大小写 re.M多行模式 re.S 将.修改为任意匹配
# re.compile(pattern,flag=0)
# 对整个整个字符串进行烧苗 对输入的正则进行匹配
# re.search(pattern,string,flags=0)
pat = re.compile(r"\d+")
# # 返回一个对象
# print(re.search(pat,"ad12cccc123"))
# # 返回一个列表 内部有匹配的值
# print(re.findall(pat,"ad12cccc123"))
url = "http://www.tipdm.com/tipdm/index.html"
ua = {"User-Agent":"Mozilla/5.0 (Windows NT 6.1; Win64; x64) Chrome/65.0.3325.181"}
res = requests.get(url,headers = ua,timeout = 3)
# 转换编码
res.encoding = chardet.detect(res.content)["encoding"]
title_pattern = r'(?<=<title>).*?(?=</title>)'
title_com = re.compile(title_pattern,re.M|re.S)
print(re.search(title_com,res.text).group())
print(re.findall(title_com,res.text))
Xpath 解析网页
XML路径语言是一门在XML文档查找信息的语言
Xpath最初被设计搜索XML文档 但是在HTML同样适用
# lxml.etree.HTML(text,parser = None,*,base_url=None)
# text: HTML字符串 parser: HTML解释器 base_url 文档初始url
html = etree.HTML(res.text,parser=etree.HTMLParser(encoding='utf-8'))
# html可以使用类似的正则匹配HTML的内容
# nodename : 选取nodename节点的全部子节点 /直接子节点 //子孙节点 . 当前节点 ..父节点 @选取属性
# resss = html.xpath('head')
# print(resss)
# res = html.xpath('html/head/title')
# print(res)
# res = html.xpath('title')
# print(res)
# xpath 类似前段
# 谓语 /html/body/div[1] 子节点的第一个div节点 div[last()] div[last()-1] div[position()<3] div[@id] div[@id="content"]
resss = html.xpath("//title/text()")
print(resss)
Beautiful Soup解析网页
# Beautiful Soup 是一个可以解析HTMl 或者 XML文件的python库 提供了简单的函数来进行导航 搜索 修改分析树等功能
# 这个库 非常简单 可以少量代码写出完整应用程序
BeautifulSoup解析html
from bs4 import BeautifulSoup
import requests
import chardet
url = "http://www.tipdm.com/tipdm/index.html"
ua = {"User-Agent":"Mozilla/5.0 (Windows NT 6.1; Win64; x64) Chrome/65.0.3325.181"}
res = requests.get(url,headers = ua)
res.encoding = chardet.detect(res.content)['encoding']
html = res.text
# soup可以将html转为复杂的树 树内有四种节点 tag navigableSring beautifulsoup comment
soup = BeautifulSoup(html,'lxml')
# tag: html中的标签 每次只能获得第一个 除非链式调用
# tag对象有两个重要的属性 name attributes
# 对于tag标签 可以使用 tag.string 获得其值
# 格式化输出
# print(soup.prettify())
# 输出 head 标签
# print(soup.head)
# 输出 body下的第一个a
# 输出全部的a
# 对于bs4 搜索特定的节点 并且获得其中的文本或者连接
# find_all(name,attrs,recursive,string,limit,**kwargs)
# name: tag attrs:符合css类名 string匹配这个字符串
# 输出文本中 名为title的子节点
print(soup.find_all('title'))
# 输出文本内容
print(soup.title.string)
# 输出内容
print(soup.title.get_text())
# 找类
print(soup.find_all('ul',class_='menu'))
# 找id
print(soup.find_all(id='menu'))
# 找到ul下的全部的a标签
tar = soup.ul.find_all('a')
urls = []
text = []
for s in tar:
urls.append(s.get('href'))
text.append(s.get_text())
for i in urls:
print(i)
for j in text:
print(j)
json与mysql
json:
json.dump(obj): 转为对象
json.dumps(obj): 转为字符串
爬取网页 解析网页标题 将数据写入数据库
将数据库和爬虫串联
import pymysql
conn = pymysql.connect(host='127.0.0.1',port=3306,user='root',passwd='kunye666',db='spider',charset='utf8')
# 创建游标
cursor = conn.cursor()
# 创建语句
# sql = '''create table if not exists class (id int(10) primary key auto_increment,name varchar(20) not null,text varchar (20) not null )'''
# # 执行语句
# cursor.execute(sql)
# cursor.execute('show tables')
import requests
import chardet
from bs4 import BeautifulSoup
url = "http://www.tipdm.com/tipdm/index.html"
ua = {"User-Agent":"Mozilla/5.0 (Windows NT 6.1; Win64; x64) Chrome/65.0.3325.181"}
# 获得网页内容
res = requests.get(url,ua,timeout = 3)
res.encoding = chardet.detect(res.content)['encoding']
html = res.text
# 获得网页标题
soup = BeautifulSoup(html,'lxml')
target = soup.title.string
print("标题:",target)
title = 'tipdm'
# 网页标题写入表内
sql = 'insert into class(name,text) values(%s,%s)'
cursor.execute(sql,(title,target))
conn.commit()
# 读取数据
cursor.execute('select * from class')
# 获得查询结果中的n条记录 fetchmany(n)
data = cursor.fetchmany()
print(data)
conn.close()