你聪明有人会说你心机重,你靠的是努力有人会说你运气好,你说自己天生乐观有人会说你虚假。有时,你明明就是一杯白水,却被硬生生逼成了满肚子憋屈的碳酸饮料。人一生遇见太多人,没必要活在他们的眼神里,只要内心澄明,就永远不用讨好一个不懂你的人。就算全世界都否定你,你也要相信你自己。
总结:
1.爬虫不是爬虫技术比较厉害,而是反爬虫成本太高了!
2.404大量出现,并且都不一样,说明有人在嗅探网站;![摄图网_401645632_banner.jpg]
3.日志编码在分析之前就要使用 UTF-8;
完成分析功能
分析日志很重要,通过海量数据分析就能够知道是否遭受了攻击,是否被爬取及爬取高峰期,是否有盗链等。
百度(Baidu) 爬虫名称(Baiduspider)
谷歌(Google) 爬虫名称(Googlebot)
一个离线日志分析项目的基本框架
1.可以指定文件或目录,对日志进行数据分析;
2.分析函数可以动态注册;
3.数据可以分发给不同的分析处理程序 进行处理;
HTTP状态码*解析
HTTP状态码(HTTP Status Code)是用以表示网页服务器HTTP响应状态的3位数字代码。它由 RFC 2616 规范定义的,并得到RFC 2518、RFC 2817、RFC 2295、RFC 2774、RFC 4918等规范扩展;
状态码(必须背,常见的7-8个)状态码中包含了很多信息。例如
- 304占比大,说明静态缓存效果明显。404占比大,说明网站出现了错误链接,或者尝试嗅探网站资源。
- 如果400、500占比突然开始增大,网站一定出问题了,一定要立刻解决。
1xx(临时响应) | 表示临时响应并需要请求者继续执行操作的状态码。 |
---|---|
100(继续) | 请求者应当继续提出请求。服务器返回此代码表示已收到请求的第一部分,正在等待其余部分。 |
101(切换协议) | 请求者已要求服务器切换协议,服务器已确认并准备切换。 |
2xx(成功) | 表示成功处理了请求的状态码。 |
200(成功) | 服务器已成功处理了请求。通常,这表示服务器提供了请求的网页。如果是对您的 robots.txt 文件显示此状态码,则表示 Googlebot 已成功检索到该文件。 |
201(已创建) | 请求成功并且服务器创建了新的资源。 |
202(已接受) | 服务器已接受请求,但尚未处理。 |
203(非授权信息) | 服务器已成功处理了请求,但返回的信息可能来自另一来源。 |
204(无内容) | 服务器成功处理了请求,但没有返回任何内容。 |
205(重置内容) | 服务器成功处理了请求,但没有返回任何内容。与 204 响应不同,此响应要求请求者重置文档视图(例如,清除表单内容以输入新内容)。 |
206(部分内容) | 服务器成功处理了部分 GET 请求。 |
3xx (重定向) | 要完成请求,需要进一步操作。通常,这些状态码用来重定向。Google 建议您在每次请求中使用重定向不要超过 5 次。您可以使用网站管理员工具查看一下 Googlebot 在抓取重定向网页时是否遇到问题。诊断下的网络抓取页列出了由于重定向错误导致 Googlebot 无法抓取的网址。 |
300(多种选择) | 针对请求,服务器可执行多种操作。服务器可根据请求者 (user agent) 选择一项操作,或提供操作列表供请求者选择。 |
301(永久移动) | 请求的网页已永久移动到新位置。服务器返回此响应(对 GET 或 HEAD 请求的响应)时,会自动将请求者转到新位置。您应使用此代码告诉 Googlebot 某个网页或网站已永久移动到新位置。 |
302(临时移动) | 服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来响应以后的请求。此代码与响应 GET 和 HEAD 请求的 301 代码类似,会自动将请求者转到不同的位置,但您不应使用此代码来告诉 Googlebot 某个网页或网站已经移动,因为 Googlebot 会继续抓取原有位置并编制索引。 |
303(查看其他位置) | 请求者应当对不同的位置使用单独的 GET 请求来检索响应时,服务器返回此代码。对于除 HEAD 之外的所有请求,服务器会自动转到其他位置。 |
304(未修改) | 自从上次请求后,请求的网页未修改过。服务器返回此响应时,不会返回网页内容。如果网页自请求者上次请求后再也没有更改过,您应将服务器配置为返回此响应(称为 If-Modified-Since HTTP 标头)。服务器可以告诉 Googlebot 自从上次抓取后网页没有变更,进而节省带宽和开销。 |
305(使用代理) | 请求者只能使用代理访问请求的网页。如果服务器返回此响应,还表示请求者应使用代理。 |
307(临时重定向) | 服务器目前从不同位置的网页响应请求,但请求者应继续使用原有位置来响应以后的请求。此代码与响应 GET 和 HEAD 请求的 <a href=answer.py?answer=>301</a> 代码类似,会自动将请求者转到不同的位置,但您不应使用此代码来告诉 Googlebot 某个页面或网站已经移动,因为 Googlebot 会继续抓取原有位置并编制索引。 |
4xx(请求错误) | 这些状态码表示请求可能出错,妨碍了服务器的处理。 |
400(错误请求) | 服务器不理解请求的语法。 |
401(未授权) | 请求要求身份验证。对于登录后请求的网页,服务器可能返回此响应。 |
403(禁止) | 服务器拒绝请求。如果您在 Googlebot 尝试抓取您网站上的有效网页时看到此状态码(您可以在 Google 网站管理员工具诊断下的网络抓取页面上看到此信息),可能是您的服务器或主机拒绝了 Googlebot 访问。 |
404(未找到) | 服务器找不到请求的网页。例如,对于服务器上不存在的网页经常会返回此代码。如果您的网站上没有 robots.txt 文件,而您在 Google 网站管理员工具“诊断”标签的 robots.txt 页上看到此状态码,则这是正确的状态码。但是,如果您有 robots.txt 文件而又看到此状态码,则说明您的 robots.txt 文件可能命名错误或位于错误的位置(该文件应当位于顶级域,名为 robots.txt)。如果对于 Googlebot 抓取的网址看到此状态码(在”诊断”标签的 HTTP 错误页面上),则表示 Googlebot 跟随的可能是另一个页面的无效链接(是旧链接或输入有误的链接)。 |
405(方法禁用) | 禁用请求中指定的方法。 |
406(不接受) | 无法使用请求的内容特性响应请求的网页。 |
407(需要代理授权) | 此状态码与 <a href=answer.py?answer=35128>401(未授权)</a>类似,但指定请求者应当授权使用代理。如果服务器返回此响应,还表示请求者应当使用代理。 |
408(请求超时) | 服务器等候请求时发生超时。 |
409(冲突) | 服务器在完成请求时发生冲突。服务器必须在响应中包含有关冲突的信息。服务器在响应与前一个请求相冲突的 PUT 请求时可能会返回此代码,以及两个请求的差异列表。 |
410(已删除) | 如果请求的资源已永久删除,服务器就会返回此响应。该代码与 404(未找到)代码类似,但在资源以前存在而现在不存在的情况下,有时会用来替代 404 代码。如果资源已永久移动,您应使用 301 指定资源的新位置。 |
411(需要有效长度) | 服务器不接受不含有效内容长度标头字段的请求。 |
412(未满足前提条件) | 服务器未满足请求者在请求中设置的其中一个前提条件。 |
413(请求实体过大) | 服务器无法处理请求,因为请求实体过大,超出服务器的处理能力。 |
414(请求的 URI 过长) | 请求的 URI(通常为网址)过长,服务器无法处理。 |
415(不支持的媒体类型) | 请求的格式不受请求页面的支持。 |
416(请求范围不符合要求) | 如果页面无法提供请求的范围,则服务器会返回此状态码。 |
417(未满足期望值) | 服务器未满足”期望”请求标头字段的要求。 |
5xx(服务器错误) | 这些状态码表示服务器在处理请求时发生内部错误。这些错误可能是服务器本身的错误,而不是请求出错。 |
500(服务器内部错误) | 服务器遇到错误,无法完成请求。 |
501(尚未实施) | 服务器不具备完成请求的功能。例如,服务器无法识别请求方法时可能会返回此代码。 |
502(错误网关) | 服务器作为网关或代理,从上游服务器收到无效响应。 |
503(服务不可用) | 服务器目前无法使用(由于超载或停机维护)。通常,这只是暂时状态。 |
504(网关超时) | 服务器作为网关或代理,但是没有及时从上游服务器收到请求。 |
505(HTTP 版本不受支持) | 服务器不支持请求中所用的 HTTP 协议版本。 |
# 没有进行面向对象封装,写的代码很难看;、
# !/usr/bin/env python
# encoding:utf-8
'''
@auther:administrator
'''
import random # 产生随机数;
import re, datetime, time, threading
from queue import Queue
#line = '''183.69.210.164 - - [07/Apr/2017:09:32:40 +0800] "GET /index.php?m=login HTTP/1.1" 200 3661 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.221 Safari/537.36 SE 2.X MetaSr 1.0"'''
# pattern = '''([\d.]{7,15}) - - \[([/\w +:]+)\] "(\w+) (\S+) ([\w/\d.]+)" (\d+) (\d+) .+ "(.+)"'''
pattern = '(?P<remote>[\d.]{7,15}) - - \[(?P<datetime>[^\[\]]+)\] "(?P<method>[^" ]+) (?P<url>[^" ]+) (?P<protocol>[^" ]+)" (?P<status>\d+) (?P<size>\d+) \S+ "(?P<userggent>[^"]*)"'
regex = re.compile(pattern)
matcher = regex.match(line)
ops = {
'datetime': lambda dstr: datetime.datetime.strptime(dstr, '%d/%b/%Y:%H:%M:%S %z'),
'status': int, 'size': int
}
# 提取
def extract(line: str):
matcher = regex.match(line)
if matcher:
return {k: ops.get(k, lambda x: x)(v) for k, v in matcher.groupdict().items()}
# print(extract(line))
# 数据源
def loadfile(filename: str,encoding='utf-8'):
with open(filename, encoding=encoding) as f:
for line in f:
fields = extract(line)
if isinstance(fields,(dict,)):
yield fields
else:
print("No match.{}".format(fields)) # TODO 解析失败就抛弃,或者打印日志
from pathlib import Path
# 文件目录加载;
def load(*paths,encoding='utf-8',ext='*.log',r=False):
"""装载日志文件"""
for p in paths:
path = Path(p)
if path.is_dir(): # 对目录处理;
if isinstance(ext,str):
ext = [ext]
for e in ext: #按照拓展名递归
logs = path.rglob(e) if r else path.glob(e)
for log in logs:
yield from loadfile(str(log.absolute()),encoding=encoding)
elif path.is_file():
loadfile(str(log.absolute()))
for x in load('test.log'):
print(x)
# 生成器;
# 模拟用的数据源
def source(seconds=1):
while True:
yield {'datetime': datetime.datetime.now(datetime.timezone(datetime.timedelta(hours=8))),
'value': random.randint(1, 100)}
time.sleep(seconds)
s = source()
# collecting date
# 分析函数、处理函数;
# 平均数
def avg_handler(iterable):
return sum(map(lambda item: item['value'], iterable)) / len(iterable)
# 状态码占比统计;
def status_handler(iterable:list): # 指的是一个时间段内的数据;
status = {}
for item in iterable: # item =》 fields
key = item['status']
status[key] = status.get(key,0) + 1 # 核心代码
total = len(iterable)
return {k:v/total for k,v in status.items()}
# 窗口函数;
def window(q: Queue, handler, width: int, interval: int):
buf = []
start = datetime.datetime.strptime('19700101 00:00:01 +0800', '%Y%m%d %H:%M:%S %z')
current = datetime.datetime.strptime('19700101 00:00:01 +0800', '%Y%m%d %H:%M:%S %z')
delta = datetime.timedelta(seconds=width - interval)
while True:
data = q.get() # 阻塞的 next(iterator)
if data:
buf.append(data)
current = data['datetime']
print(current, start)
if (current - start).total_seconds() > interval:
print('~~~~~~~~~~~~~')
ret = handler(buf)
print('{:.2f}'.format(ret))
print(threading.current_thread())
start = current
# clean old_date
buf = [x for x in buf if x['datetime'] > current - delta]
# 分发器,数据的调入;
def dispatcher(src):
handlers = [] # 线程对象,但是里面实际上是不同的handler;
queues = []
def reg(handler, width, interval): # 数据谁,handler、width、interval ;
q = Queue()
t = threading.Thread(target=window, args=(q, handler, width, interval))
queues.append(q)
handlers.append(t)
def run():
for t in handlers:
t.start()
while True:
data = next(src)
for q in queues:
q.put(data)
return reg, run
if __name__ == ' __main__ ':
import sys
src = load('test.log')
for x in s:
print(x)
reg, run = dispatcher(src)
reg(donothing_handler,10,5) # 注册处理函数;
reg(avg_handler, 10, 5)
# reg(avg_handler,10,5)
# window(s,avg_handler,10,5)
# run()
print(threading.current_thread())
run()
#---------------------------------------------
浏览器分析uergent
这里指的是,软件按照一定的格式向远端的服务器提供一个标识自己的字符串。
在HTTP协议中,使用user-agent字段传送这个字符串。
现在浏览器的user-agent值格式一般如下:
Mozilla/[version] ([system and browser information]) [platform] ([platform details]) [extensions]
信息提取
依赖 pyyaml、ua-parser、user-agents模块;
pip install pyyaml ua-parser user-agents
from user_agents import parse
uastr = """
Mozilla/5.0 (Windows; U; Windows NT 6.1; zh-CN) AppleWebKit/537.36 (KHTML, like Gecko) Version/5.0.1 Safari/537.36
"""
ua = parse(uastr)
print(ua,type(ua)) # 系统 浏览器信息 ;
print(ua.browser) # 浏览器信息
print(ua.browser.family,ua.browser.version_string) # 浏览器+版本信息;
#-------------------------------------------------------------------------------------------------------
PC / Windows 7 / Safari 5.0.1 <class 'user_agents.parsers.UserAgent'>
Browser(family='Safari', version=(5, 0, 1), version_string='5.0.1')
Safari 5.0.1
# !/usr/bin/env python
# encoding:utf-8
'''
@auther:administrator
'''
import random # 产生随机数;
import re, datetime, time, threading
from queue import Queue
from pathlib import Path
from user_agents import parse
#line = '''183.69.210.164 - - [07/Apr/2017:09:32:40 +0800] "GET /index.php?m=login HTTP/1.1" 200 3661 "-" "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.221 Safari/537.36 SE 2.X MetaSr 1.0"'''
# pattern = '''([\d.]{7,15}) - - \[([/\w +:]+)\] "(\w+) (\S+) ([\w/\d.]+)" (\d+) (\d+) .+ "(.+)"'''
pattern = '(?P<remote>[\d.]{7,15}) - - \[(?P<datetime>[^\[\]]+)\] "(?P<method>[^" ]+) (?P<url>[^" ]+) (?P<protocol>[^" ]+)" (?P<status>\d+) (?P<size>\d+) \S+ "(?P<userggent>[^"]*)"'
regex = re.compile(pattern)
#matcher = regex.match(line)
ops = {
'datetime': lambda dstr: datetime.datetime.strptime(dstr, '%d/%b/%Y:%H:%M:%S %z'),
'status': int, 'size': int
}
# 提取
def extract(line: str):
matcher = regex.match(line)
if matcher:
return {k: ops.get(k, lambda x: x)(v) for k, v in matcher.groupdict().items()}
else:
return line
# print(extract(line))
# 数据源
def loadfile(filename: str,encoding='utf-8'):
with open(filename, encoding=encoding) as f:
for line in f:
fields = extract(line)
if isinstance(fields,(dict,)):
yield fields
else:
pass
#print("No match.{}".format(fields)) # TODO 解析失败就抛弃,或者打印日志
# 文件目录加载;
def load(*paths,encoding='utf-8',ext='*.log',r=False):
"""装载日志文件"""
for p in paths:
path = Path(p)
if path.is_dir(): # 对目录处理;
if isinstance(ext,str):
ext = [ext]
for e in ext: #按照拓展名递归
logs = path.rglob(e) if r else path.glob(e)
for log in logs:
yield from loadfile(str(log.absolute()),encoding=encoding)
elif path.is_file():
loadfile(str(log.absolute(),encoding=encoding))
#
# 生成器;
# 模拟用的数据源
def source(seconds=1):
while True:
yield {'datetime': datetime.datetime.now(datetime.timezone(datetime.timedelta(hours=8))),
'value': random.randint(1, 100)}
time.sleep(seconds)
s = source()
# collecting date
# 分析函数、处理函数;
# 平均数
def avg_handler(iterable):
return sum(map(lambda item: item['value'], iterable)) / len(iterable)
# 状态码占比统计;
def status_handler(iterable:list): # 指的是一个时间段内的数据;
status = {}
for item in iterable: # item =》 fields
key = item['status']
status[key] = status.get(key,0) + 1 # 核心代码
total = len(iterable)
return {k:v/total for k,v in status.items()}
allbroswers = {}
# 浏览器数目 分析;
def browser_handler(iterable):
browser = {}
for item in iterable: #item=>fields
uastr = item['useragent']
ua = parse(uastr)
key = ua.browser.family,ua.browser.version_string # 元组类型()
browsers[key] = browsers.get(key,0) + 1
allbrowsers[key] = allbrowsers.get(key, 0) + 1
return browsers
# 窗口函数;
def window(q: Queue, handler, width: int, interval: int):
buf = []
start = datetime.datetime.strptime('19700101 00:00:01 +0800', '%Y%m%d %H:%M:%S %z')
current = datetime.datetime.strptime('19700101 00:00:01 +0800', '%Y%m%d %H:%M:%S %z')
delta = datetime.timedelta(seconds=width - interval)
while True:
data = q.get() # 阻塞的 next(iterator)
if data:
buf.append(data)
current = data['datetime']
#print(current, start)
if (current - start).total_seconds() > interval:
print('~~~~~~~~~~~~~')
ret = handler(buf)
print('{}'.format(ret))
#print(threading.current_thread())
start = current
# clean old_date
buf = [x for x in buf if x['datetime'] > current - delta]
# 分发器,数据的调入;
def dispatcher(src):
handlers = [] # 线程对象,但是里面实际上是不同的handler;
queues = []
def reg(handler, width, interval): # 数据谁,handler、width、interval ;
q = Queue()
t = threading.Thread(target=window, args=(q, handler, width, interval))
queues.append(q)
handlers.append(t)
def run():
for t in handlers:
t.start()
while True:
#data = next(src)
for data in src:
for q in queues:
q.put(data)
print('================')
while True: # 另加
cmd = input('>>>')
if cmd =='':
print(allbroswers)
newdict = {}
for (k,ver),val in allbroswers.items():
newdict[k] = newdict.get(k,0) + val
print(sorted(newdict.items(),key=lambda item:item[1],reverse=True))
return reg, run
if __name__ == ' __main__ ':
import sys
src = load('test.log')
reg, run = dispatcher(src)
reg(status_handler,10,5) # 注册处理函数;
reg(browser_handler, 10, 10)
# reg(avg_handler,10,5)
# window(s,avg_handler,10,5)
# run()
#print(threading.current_thread())
run()
网友评论