前些天一直在刷题,不过都是一些挺简单的,然后有几道需要python脚本的题可谓是把我弄了一波,认认真真地去学习了一波python以及正则。就聊一下这几道题收获吧。

Python

Requests

首先是python requests库的学习

对于request的回显如果显示乱码的话,可以添加

1
rep.encoding = 'utf-8'

进阶用法可以用

1
r = requests.session()

用来保持会话,以及可以直接实现带cookie二次访问

1
2
3
4
#比如第一次建立链接
rep = r.get('xxx.com')
#第二次需要post数据,以及以上次的cookie访问
rep2 = r.post('xxx.com',data=data)

这就很方便了,不需要再单独记录cookie来确定是同一次session了

还有python的正则库re

1
2
3
4
5
import re
pattern = re.compile(r'^[^=]*')
match = pattern.match(yourString)
if match:
print match.group(0)

在re.compile引号中输入你的正则表达式,然后进行匹配

exec、eval、represents

exec语句用来执行储存在字符串或文件中的Python语句。例如,我们可以在运行时生成一个包含Python代码的字符串,然后使用exec语句执行这些语句。

1
exec("print('Hello World')")

运行结果:

Hello World

eval语句用来计算存储在字符串中的有效Python表达式。

1
eval_r("2 * 3")

运行结果:

6

repr函数用来取得对象的规范字符串表示。注意,在大多数时候有eval_r(repr(object)) == object。

可以参考Python中repr与str区别

执行shell命令

  1. os.system

    os模块中的os.system()这个函数来执行shell命令

    os.system('ls')

    输出结果:

    Appalication Desktop Downloads

    print os.system('mkdir test')

    输出结果:

    0

    可以看到结果打印出0,表示命令执行成功;否则表示失败(再次执行该命令,输出:子目录或文件 test 已经存在。1)

    再次执行:

    mkdir: test: File exists

    256

    注,这个方法得不到shell命令的输出。

  2. popen()

    这个方法能得到命令执行后的结果是一个字符串,要自行处理才能得到想要的信息。

    1
    2
    3
    4
    5
    import os
    str = os.popen("ls").read()
    a = str.split("\n")
    for b in a:
    print b

    输出结果与os.system('ls')一致

  3. commands模块

    可以很方便的取得命令的输出(包括标准和错误输出)和执行状态位

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    import commands
    a,b = commands.getstatusoutput('ls')
    a是退出状态
    b是输出的结果。
    >>> import commands
    >>> a,b = commands.getstatusoutput('ls')
    >>> print a
    0
    >>> print b
    Application
    Desktop
    Downloads

    commands.getstatusoutput(cmd)返回(status,output)

    commands.getoutput(cmd)只返回输出结果

    commands.getstatus(file)返回ls -ld file 的执行结果字符串,调用了getoutput,不建议使用这个方法。

  4. subprocess模块

    使用subprocess模块可以创建新的进程,可以与新建进程的输入/输出/错误管道连通,并可以获得新建进程执行的返回状态。使用subprocess模块的目的是替代os.system()、os.popen()、commands.等旧的函数或模块。

    1
    2
    3
    4
    5
    6
    7
    import subprocess
    subprocess.call(command, shell=True)
    #会直接打印出结果。
    subprocess.Popen(command, shell=True)
    #也可以是subprocess.Popen(command, stdout=subprocess.PIPE, shell=True) 这样就可以输出结果了。
    #如果command不是一个可执行文件,shell=True是不可省略的。
    #shell=True意思是shell下执行command

正则表达式

正则表达式自己还是有点弱,主要是一些原理自己有点懒得去了解,就导致每次写正则自己都很蠢…

转载改编自:正则表达式 - 贪婪与非贪婪(惰性)(侵删)

使用场景

有时,我们想用正则匹配以某个子串开头,且以某个子串或字符结尾的子字符串,但是结尾的字串或字符在原字符串中出现了多次,但我们只想匹配从开始处到第一次出现的地方,换句话说,想得到开始和结尾之间内容最少的匹配

正则的贪婪与非贪婪(惰性)

通常使用如下字符类描述前导字符的重复特征:

  1. ?: 告诉引擎匹配前导字符0次或一次。事实上是表示前导字符是可选的。

  2. +: 告诉引擎匹配前导字符1次或多次。

  3. *: 告诉引擎匹配前导字符0次或多次。

  4. {min, max}: 告诉引擎匹配前导字符min次到max次。min和max都是非负整数。如果有逗号而max被省略了,则表示max没有限制;如果逗号和max都被省略了,则表示重复min次。
    因此 {0,} 和 * 一样,{1,} 和 + 的作用一样。

贪婪与非贪婪

贪婪 : 默认情况下,? + * {min, max}都是贪婪的,也就是说,它会根据前导字符去匹配尽可能多的内容。

非贪婪(惰性) : 非贪婪就是匹配尽可能少的内容。

原理浅析

结合实例来分析哈基于正则的引擎对文本的匹配过程。原始字符串:This is a <EM>first</EM> test,使用正则<.+>来匹配HTML标签,期望第一次匹配得到<EM>,第二次匹配得到</EM>,实际却是第一次匹配就得到了<EM>first</EM>

来看看匹配过程,第一个记号是<,这是一个文本字符,匹配其自身。第二个符号是.,匹配了字符E,然后+一直可以匹配其余的字符,直到一行的结束。然后到了换行符,匹配失败(.不匹配换行符)。于是引擎开始对下一个正则表达式符号进行匹配,即试图匹配>。到目前为止,<.+已经匹配了<EM>first</EM> test。引擎会试图将>与换行符进行匹配,结果失败了。于是引擎进行回溯。回溯后的匹配状况是 <.+ 匹配 <EM>first</EM> tes。于是引擎将>t进行匹配。显然还是会失败。这个过程继续,直到 <.+ 匹配 <EM>first</EM>>匹配。于是引擎找到了一个匹配<EM>first</EM>。记住,正则导向的引擎是急切的,所以它会急着报告它找到的第一个匹配。而不是继续回溯,即使可能会有更好的匹配,例如<EM>。所以我们可以看到,由于+的贪婪性,使得正则表达式引擎返回了一个最左边的最长的匹配。

如果想得到期望的结果,就需要启用非贪婪模式:<.+?>

总结:如果是贪婪匹配模式,正则引擎会一直匹配到字符串最后;当匹配为false时,就回溯以找到倒数第一个匹配位置,返回匹配结果。 如果是非贪婪匹配模式,正则引擎会匹配到符合pattern的末尾位置那个字符,然后再往后走一步,发现匹配为false时,就回溯以找到最近一个匹配为true的位置,返回匹配结果。

实例

例如,原始字符串:

1
{"accesskey":{"acccessKeyId":"XhUURxsMlJE6EiXf","accessKeySecret":"Q9fMpgBgRnKycMRD28MMkkFMbiNkbY"},"dbGrant":{"0000031736":"READWRITE"},"dbSchemaId":"0000031737"}

现在想把这部分敏感信息替换为空字符串:

1
"accesskey":{"acccessKeyId":"XhUURxsMlJE6EiXf","accessKeySecret":"Q9fMpgBgRnKycMRD28MMkkFMbiNkbY"},

先不考虑结尾的逗号,尝试正则:"accesskey":\{.+\},直接匹配至原始字符串结尾的}字符,因为引擎默认会匹配尽可能多的内容。

考虑到贪婪性,将正则修改为:"accesskey":\{.+\}+?,匹配结果一样。纳尼?难道我对贪婪性的理解有问题。梳理哈使用姿势,我期望它匹配到开始位置之后出现的第一个}字符,对应的表达式部分为}+?。套用非贪婪模式分析问题,期望对一个或多个}字符进行匹配,且匹配尽可能少的内容,但在原始串中,}字符都是分开的,没有连续,无论如何只能匹配一个单独的}字符。可见对}字符开启非贪婪模式匹配行不通。

想要匹配到开始位置之后出现的第一个}字符 也可以表达为 开始位置和末尾}字符之间的内容最少,对应正则部分修改为:.+?,完整表达式:"accesskey":\{.+?\},测试匹配结果,妥妥的。

以上均为转载,这里讲讲自己的实例

1
sid=14d8f776-a969-4252-b35a-f83a807e7f2d;userName=111111111;

目的是匹配

1
sid=14d8f776-a969-4252-b35a-f83a807e7f2d;

一开始自己瞎糊弄了半天,最后找到了比较接近的sid=.*;,可是这个直接匹配到了行末,把userName一起包含进去了,这时候就要考虑到非贪婪性了,即sid=.*?;就可以匹配到第一个遇到的;

又如

1
1087080534*1062477688-245892309-863670697+1430950488-2128604487+787613783-929770459-331572804*1754549713+81041939=?;

匹配前面的算数表达式(=前面的表达式不包括=

自己也瞎糊弄了好久,一开始写的是.*=死活都包含了=,这就很烦了

然后认真去看了正则,用了[^],解释是

Match any character that is not in the set.

就是匹配任何不包含这个字符的字符串

所以最后是^[^=]*

还有对于

1
跑的还不错,给你flag吧: NzI3NTY3

匹配最后的base64字符串,之前考虑的是(?=:).*

但是还是老问题老是匹配了:?<在python中不能用…这就比较麻烦了

然后查了一下发现可以用group来弄,差不多就是给他们分组的意思

1
(.*)(: )(.*)

这就分成了三组,第一组匹配的是中文,第二组匹配的是:,第三组匹配的就是最后的字符串,所以我们只需要提取group(3)就好了。

Tmux配置记录

详情参考tmux配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#-- base --#
set -g default-terminal "screen-256color"
set -g display-time 3000
set -g history-limit 10000
set -g base-index 1
set -g pane-base-index 1
set -s escape-time 0
set -g mouse on
#-- bindkeys --#
# split windows like vim. - Note: vim's definition of a horizontal/vertical split is reversed from tmux's
unbind s
bind s split-window -v
bind S split-window -v -l 40
bind v split-window -h
bind V split-window -h -l 120
# navigate panes with hjkl
bind h select-pane -L
bind j select-pane -D
bind k select-pane -U
bind l select-pane -R
# key bindings for horizontal and vertical panes
unbind %
bind | split-window -h # 使用|竖屏,方便分屏
unbind '"'
bind - split-window -v # 使用-横屏,方便分屏
# swap panes
bind ^u swapp -U
bind ^d swapp -D
bind q killp
bind ^e last
unbind r
bind r source-file ~/.tmux.conf \; display "Configuration Reloaded!"
#-- statusbar --#
set -g status-justify centre
set -g status-left "#[fg=red]s#S:w#I.p#P#[default]"
set -g status-right '[#(whoami)#(date +" %m-%d %H:%M ")]'
set -g status-left-attr bright
set -g status-left-length 120
set -g status-right-length 120
set -g status-utf8 on
set -g status-interval 1
set -g visual-activity on
setw -g monitor-activity on
setw -g automatic-rename off
# default statusbar colors
set -g status-bg colour235 #base02
set -g status-fg colour136 #yellow
set -g status-attr default
# default window title colors
setw -g window-status-fg colour244
setw -g window-status-bg default
#setw -g window-status-attr dim
# active window title colors
setw -g window-status-current-fg colour166 #orange
setw -g window-status-current-bg default
#setw -g window-status-current-attr bright
# window title string (uses statusbar variables)
set -g set-titles-string '#T'
set -g status-justify "centre"
set -g window-status-format '#I #W'
set -g window-status-current-format ' #I #W '
# pane border
set -g pane-active-border-fg '#55ff55'
set -g pane-border-fg '#555555'
# message text
set -g message-bg colour235 #base02
set -g message-fg colour166 #orange
# pane number display
set -g display-panes-active-colour colour33 #blue
set -g display-panes-colour colour166 #orange
# clock
setw -g clock-mode-colour colour64 #green
# 修改进入命令模式按键
# remap prefix to Control + a
# set -g prefix C-a
# unbind C-b
# bind C-a send-prefix