0x00 MVC框架

MVC框架的理念就是:分工,让专门的人做专门的事

M:Model模型,与数据库进行交互

V:View视图,产生HTML页面

C:Controller控制器,接收请求,进行处理,与M和V进行交互,返回应答

从一个注册的交互过程理解MVC工作原理

0x01 Django的MVT框架

Django是一个遵循MVC的python Web框架, 但是他的框架模式有自己的名字:MVT

M:Model模型,和MVC中M功能相同,和数据库进行交互。

V:View视图,和MVC中C功能相同,接受请求进行处理,与M和T进行交互。

T:Template模板,和MVC中V相同,产生HTML页面。

区别是以V代替了原来的C,同T和M进行交互。

0x02 虚拟环境的安装

在python中如果安装一个包的不同版本,后安装的会将原来安装的包覆盖掉,在实际开发中若遇到使用同一个包的不同版本的情况则就无法同时兼得,遇是就使用了虚拟环境来进行操作。

安装虚拟环境的命令:

这里以ubuntu18.04为例

1)sudo pip install virtualenv#安装虚拟环境
2)sudo pip install virtualenvwrapper#安装成拟环境扩展包
3)编辑家目录下面的bashrc文件,添加下面两行。
export WORKON_HOME=$HOME/.virtualenvs
source /usr/local/bin/virtualenvwrapper.sh
4)使用source .bashrc使其生效一下。

创建虚拟环境:mkvirtualenv test3(名字)#这样默认是python2的环境

mkvirtualenv -p python3 test(名字)#这样是python3的环境

执行完毕后进入其目录(虚拟环境就是真是python环境的复制版)

在Home目录下输入【Ctrl】+【H】显示出隐藏文件,就可以找到 .virtualenvs文件夹

可以建立多个虚拟环境,同时若给虚拟环境中的python安装依赖包直接pip安装即可,如果加上sudo前缀就会加到真实环境中,而不加sudo安装的结果在如下目录中。

退出虚拟环境输入deactivate,重新进入虚拟环境目录输入workon再按两下【Tab】键即可快速列出所存在虚拟环境并选择进入。

删除虚拟环境:rmvirtualenv test(虚拟环境名)

0x03 Django

虚拟环境下安装Django1.8.2版本

(test) xiaoteng@ubuntu:~$ pip install django==1.8.2

项目创建 命令:django-admin startproject test1(项目名)

init.py 说明test1是一个python包
settings.py 项目配置文件
urls.py 进行url路由的配置
wsgi.py Web服务器和Django的入口
manage.py 项目的管理文件

一个项目由很多个应用组成的,每一个应用完成一个特定的功能。
创建应用的命令如下:
python manage.py startapp 应用名

注意:创建应用时需要先进入项目目录。

init.py 说明目录是一个python模块
models.py 写和数据库项目的内容
views.py 接收请求,进行处理,与M和T进行交互,返回应答
定义处理函数,视图函数。
tests.py 写测试代码的文件
admin.py 网站后台管理相关的文件

建立应用和项目之间的联系,需要对应用进行注册。
修改settings.py中的INSTALED_APPS配置项。

(test) xiaoteng@ubuntu:~/django/test1/test1$ vi settings.py

启动服务(默认在8000端口):python manage.py runserver

启动后访问127.0.0.1:8000即可。

0x00 简介

Matplotlib是Python的一个2D图形库,能够生成各种格式的图形(诸如折线图,散点图,直方图等等),界面可交互(可以利用鼠标对生成图形进行点击操作),同时该2D图形库跨平台,即既可以在Python脚本中编码操作,也可以在Jupyter Notebook中使用,以及其他平台都可以很方便的使用Matplotlib图形库,而且生成图形质量较高,甚至可以达到出版级别。

0x01 折线图绘制

1)plt.plot(x,y,format_string,**kwargs) 
x轴数据,y轴数据,format_string控制曲线的格式字串

颜色字符说明标记字符说明标记字符说明标记字符说明风格字符说明
b蓝色.点标记1下花三角标记h竖六边形标记━ 实线
g绿色,像素标记2上花三角标记H横六边形标记━ ━ 破折线
r红色o实心圈标记3左花三角标记+十字标记━ .点划线
c青绿色v倒三角标记4右花三角标记xx标记:虚线
m洋红色^上三角标记s实心方形标记D菱形标记无线条
y黄色>右三角标记p实心五角标记d瘦菱形标记
k黑色<左三角标记*星型标记|垂直线标记
w白色
#引入pyplt,修改名称为plt
import matplotlib.pyplot as plt
#对应坐标编写折线图
plt.plot([1,2,3,6],[4,5,8,1],'g-s')
#类似print,将图形显示输出
plt.show()

2)在matplotlib中,整个图表为一个figure对象 每一个弹出的小窗口就是一个Figure对象 plt.figure(num,figsize,dpi,**kwargs)其中num为对应窗口数,figsize为窗口大小,dpi为清晰度,值越大越清晰

#引入pyplt,修改名称为plt 
import matplotlib.pyplot as plt
#设置figsize对应宽高
plt.figure(num=3,figsize=(10,10),dpi=10)
#对应坐标编写折线图
plt.plot([1,2,3,6],[4,5,8,1],'g-s')
#类似print,将图形显示输出
plt.show()

3)保存图片plt.savefig(‘路径’)

例:plt.savefig(‘./1.png’),在plt.show前添加,运行后会在当前路径下生成1.png保存刚刚绘制的图形。

4)设置刻度

#引入pyplt,修改名称为plt
import matplotlib.pyplot as plt
#设置figsize对应宽高
plt.figure(figsize=(18,10),dpi=80)
#对应坐标编写折线图
x = range(2,26,2)
y = [15,13,14.5,17,20,25,26,26,27,22,18,15]
plt.plot(x,y,'g-s')
#设置x轴刻度
plt.xticks(x)
#设置x轴中带有0.5刻度
# x1 = [i/2 for i in range(4,51)]
# plt.xticks(x1)
#设置y轴刻度
plt.yticks(range(min(y),max(y)+1))
#类似print,将图形显示输出
plt.show()

0x02 CTF中应用

[INSHack2019]Drone Motion

题目下载

一道坐标题,通过正则匹配提取坐标,画图即可。要注意的是,因为是画图,所以每个坐标每一位要加上前面的所有坐标

在sensors.log中看到以下内容

给出了坐标点,那么绘图脚本如下,引用root师傅的脚本:

import re

import matplotlib.pyplot as plt
x = []
y = []
z = []
a = []
x2,y2,z2=0,0,0
lines = open("sensors.log").readlines()
for line in lines:
    a.append("".join(re.findall("\[drone\]\(DEBUG\)> dir: \(x=(.*?),y=",line)))
for i in a:
    if i != '':
        x2+=float(i)
        x.append(float(x2))
a.clear()
for line in lines:
    a.append("".join(re.findall("\[drone\]\(DEBUG\)> dir: \(x=.*?,y=(.*?),z=",line)))
for i in a:
    if i != '':
        y2+=float(i)
        y.append(float(y2))
a.clear()
for line in lines:
    a.append("".join(re.findall("\[drone\]\(DEBUG\)> dir: \(x=.*?,y=.*?,z=(.*?)\)",line)))
for i in a:
    if i != '':
        z2+=float(i)
        z.append(float(z2))
ax = plt.plot(x, y,'-')
plt.axis('equal')# 把单位长度都变的一样 
plt.show()
plt.savefig("test.png", dpi=1000) 

0x03 总结学习

更多 matplotlib 模块的学习可参看:https://zhuanlan.zhihu.com/p/33270402

https://blog.csdn.net/qiurisiyu2016/article/details/80187177

0x00 简介

什么叫序列化:将原本的字典、列表等内容转换成一个字符串的过程就叫做序列化。字符串是有顺序的,普遍所说的序列化都是转向一个字符串的过程。

在写文件(数据存储)、网络上传输(只能传bytes)时只能对字符串进行操作,所以基于这些情况必须把“字典”等转为字符串才行。

序列化的目的:

1、以某种存储形式使自定义对象持久化

2、将对象从一个地方传递到另一个地方。

3、使程序更具维护性。

# 从数据类型 –> 字符串的过程 序列化

# 从字符串 –> 数据类型的过程 反序列化

几个重要的模块:json、pickle、shelve ,其中json和pickle专门处理json格式

0x01 json模块

json   模块提供了四个方法: dumps、dump、loads、load

python的基本数据类型:数字int,布尔值bool,字符串str,列表list,元组tuple,字典dict

(1)dumps和dump   序列化方法

dumps:将python的基本数据类型序列化为字符串
dump :将python的基本数据类型序列化成字符串并写入文件中

>>> import json
>>> json.dumps([])#dumps可以格式化所有的基本数据类型为字符串
'[]'
>>> list = ['1','2','3']#列表中元素双引号包裹也是下面结果输出
>>> json.dumps(list)#列表
'["1", "2", "3"]'         
>>> json.dumps(1)#数字
'1'
>>> json.dumps('1')#字符串
'"1"'
>>> dict = {"name":"purplet","age":23}
>>> json.dumps(dict)#字典
'{"name": "purplet", "age": 23}'
>>> tup = (1, 2, 3, 4, 5 )#元组
>>> json.dumps(tup)
'[1, 2, 3, 4, 5]'      

​从上面的转换中也可以看出输出的结果全都是字符串类型

import json
a = {"name":"purplet", "age":20}
with open("test.json", "w", encoding='utf-8') as f:
    # indent 超级好用,格式化保存字典,默认为None,不进行格式化,当indent小于等于0时格式化为零个空格
    f.write(json.dumps(a),indent=4)
    # json.dump(a,f,indent=4)   # 和上面的效果一样

​输出:

{
"name": "purplet",
"age": 20
}

当写入的字典格式文件中存在中文时,如果不加上ensure_ascii=False,默认会将其转换为unicode编码

import json
a = {"name":"张三", "age":18}
with open("test.json", "w", encoding='utf-8') as f:
# indent 超级好用,格式化保存字典,默认为None,不进行格式化,indent小于等于0时格式化为零个空格
f.write(json.dumps(a,ensure_ascii=False,indent=4))
# json.dump(a,f,indent=4) # 和上面的效果一样

(2)loads 和 load反序列化方法

loads 反序列化:将字符串反序列化成python的基本数据类型
load 反序列化:读取文件字符串,反序列化成python的基本数据类型

import json
#字典
dict_str = '{"k1":"v1","k2":"v2"}'
dict_json = json.loads(dict_str)
print(dict_json)
print(type(dict_json))
#整形
number_str = '1'
number_json = json.loads(number_str)
print(number_json)
print(type(number_json))
#列表
list_str = '[1,2,3]'
list_jaon = json.loads(list_str)
print(list_jaon)
print(type(list_jaon))
#元组
#元组与列表一致

输出:

{'k1': 'v1', 'k2': 'v2'}
<class 'dict'>
1
<class 'int'>
[1, 2, 3]
<class 'list'>

​ 从上面的转换中也可以看出输出的结果全都是python数据类型

import json

f = open('test.json','r',encoding='utf-8')#内容包含中文需编码utf-8
res = json.load(f)
print(res)

输出:{‘name’: ‘张三’, ‘age’: 18}

json强调:json格式没有单引号,只有双引号

0x02 pickle模块

该模块同样具备load loads dump dumps四个方法

import pickle

dic = {'name': 'purplet', 'age': 20, 'sex': 'male'}

print(type(dic))  # <class 'dict'>

j = pickle.dumps(dic)
print(type(j))  # <class 'bytes'>

f = open('序列化对象_pickle', 'wb')  # 注意是w是写入str,wb是写入bytes,j是'bytes'
f.write(j)  # -------------------等价于pickle.dump(dic,f)

f.close()
# -------------------------反序列化
import pickle

f = open('序列化对象_pickle', 'rb')

data = pickle.loads(f.read())  # 等价于data=pickle.load(f)

print(data['age'])#20

同时文件的读写都是byte类型,而且对于pickle来讲可以分次序列化/反序列化(json这样就会报错)。

import pickle
import time
struct_time1 = time.localtime(100000000)
struct_time2 = time.localtime(200000000)
f = open('pickle_text','wb')
pickle.dump(struct_time1,f)#json模块一样不加s的对文件操作
pickle.dump(struct_time2,f)
f.close()
#文件中内容
# ctime
# struct_time
# q (MKKKK.K(KK>K tq}q(X tm_zoneqX ?D1¨²¡À¨º¡Á?¨º¡À??qX tm_gmtoffqMpuqRq.ctime
# struct_time
# q (MKKKK!KKK}K tq}q(X tm_zoneqX ?D1¨²¡À¨º¡Á?¨º¡À??qX tm_gmtoffqMpuqRq.
f = open('pickle_text','rb')
struct_time1 = pickle.load(f)
struct_time2 = pickle.load(f)
print(struct_time1)
print(struct_time2)

文章参考Root师傅的博客:https://shawroot.cc/archives/901

1.Socket的实例化

socket(family,type[,protocal])

其中,三个参数中的family是要使用的地址族。常用的协议族有AF_INET、AF_INET6、AF_LOCAL(或称AF_UNIX、UNIX域socket)、AF_ROUTE等。默认值为socket.AF_INET,通常使用这个默认值即可。

第二个参数type用来指明Socket类型,这里可以使用的值有三个:SOCKET_STREAM,这是TCP类型,保证数据顺序及可靠性;SOCKET_DGREAM,用于UDP协议,不保证数据接收的顺序,非可靠连接;SOCK_RAW,这是原始类型,允许对底层协议如IP或ICMP进行直接访问,基本不会用到。默认值是SOCKET_STREAM。

第三个参数指使用的协议,这个参数可选。通常赋值“0”,由系统自动选择。

如果希望初始化一个TCP类型的Socket,就可以使用如下语句:

s = socket.socket()

这条语句实际上相当于socket.socket(socket.AF_INET,socket.SOCK_STREAM).因为是默认值所以可以省略。

2.Socket常用的函数

bind():这个函数由服务端Socket调用,会将之前创建Socket与指定的IP地址和端口进行绑定。如果之前使用了AF_INET初始化Socket,那么这里可以使用元组(host,port)的形式表示地址。

例如,要将刚才创建的Socket套接字绑定到本机的2345端口,就可以使用如下语句。

s.bind((‘127.0.0.1’,2345))

listen():这个函数用于在使用TCP的服务端开启监听模式。这个函数可以使用一个参数来指定可以挂起的最大连接数量。最小为:1,最大为:5

accept():这个函数用于在使用哦个TCP的服务端接收连接,一般是阻塞态。接收TCP连接并返回(conn,address),其中,conn是新的套接字对象,可以用来接收和发送数据;address是连接客户端的地址。

上面三个函数是用于服务端的Socket函数,下面介绍客户端函数。

connect():这个函数用于在使用TCP的客户端去连接服务端时使用,使用的参数是一个元组,形式为:(hostname,port)

例如:s.connect((“127.0.0.1”,2345))

两者皆可使用的函数

send():这个函数用于在使用TCP时发送数据,完整的形式为send(string[,flag]),利用这个函数可以将string代表的数据发送到已经连接的Socket,返回值是发送字节的数量。但是可能未将指定的内容全部发送。

sendall():这个函数与send()类似,也是用于TCP时发送数据,完整的形式为sendall(string[,flag]) 。区别是完整发送TCP数据。将string中的数据发送到连接的套接字,但在返回之前会尝试发送所有数据。成功返回None,失败则抛出异常

例如:s.sendall(bytes(“Hello World”,encoding=”utf-8″))

recv():这个函数用于在使用TCP时接收数据,完整的形式为recv(bufsize[,flag]),接收Socket数据。数据以字符串形式返回,bufsizez指定最多可以接收的数量,flag这个参数一般不用。

例如:dataSocket.recv(1024)

sendto():这个函数用于在使用UDP发送数据,完整的形式为sendto(string[,flag],address),返回值是发送的字节数。address是形式为(ipaddr,port)的元组,指定远程地址。

revfrom():UDP专用,接收数据,返回数据远端的IP地址和端口,但返回值是(data,address)。其中,data是包含接受数据的字符串,address是发送数据的套接字地址。

close():关闭Socket

一个交互程序

先运行服务端,再运行客户端。

server.py

# ===TCP 服务端程序 server.py ===
# 导入socket库
from socket import *
# 主机地址为0.0.0.0,表示绑定本机所有网络接口ip地址
# 等待客户端来连接
IP = '127.0.0.1'#表示可连接所有
# 端口号
PORT = 5000
#定义一次从socket缓冲区最多读入512个字节数据
BUFLEN = 512
# 实例化一个socket对象
# 参数AF_INET 表示该socket网络层使用IP协议
# 参数SOCK_STREAN 表示该socket传输层使用tcp协议
listenSocket = socket(AF_INET,SOCK_STREAM)

# socket绑定地址和端口
listenSocket.bind((IP,PORT))

# 使socket处于监听状态,等待客户端的连接请求
# 参数5表示最多接受多少个等待连接的客户端
listenSocket.listen(5)#用于监听的socket
print(f'服务端启动成功,在{PORT}端口等待客户端连接……')

dataSocket,addr=listenSocket.accept()#返回是一个元组,包含两个对象,此时的dataSocket是一个用于通信的新的socket
print('接受一个客户端连接:',addr)
while True:
#尝试读取对方发运的消息
#BUFLEN指定从接收缓冲里最多读取多少字节
recved = dataSocket.recv(BUFLEN)

#如果返回空bytes,表示对方关闭了连接
#退出循环,猪束消息收发
if not recved:
break

#读取的字节数据是bytes类型,需要解码为字符串
info = recved.decode()#发送的不同格式的信息解码不同,这里是发送字符串所以是bytes
print(f'收到对方信息:{info}')

#发运的数据类型必须是bytes,所以要编码
dataSocket.send(f'服务端接收到了信息{info}'.encode())

#服务端也调用close关闭socket
dataSocket.close()
listenSocket.close()

client.py

# ===TCP客户端程序client .py ===
from socket import *

IP = '127.0.0.1'
SERVER_PORT = 5000
BUFLEN = 512

#实例化一个socket对象指明协议
dataSocket = socket(AF_INET,SOCK_STREAM)

#链接服务端socket
dataSocket.connect((IP,SERVER_PORT))

while True:
#从终端输入用户输入的字符
toSend = input('>>>')
if toSend == 'exit':
break
# 发送消息也要编码为bytes
dataSocket.send(toSend.encode())

# 等待接收服务端的消息
recved = dataSocket.recv(BUFLEN)
#如果返回了空bytes,表示对方关闭了链接
if not recved:
break
# 打印读取的信息
print(recved.decode())

dataSocket.close()

前提有python2,这个不要删,我们再装一个python3

首先安装依赖包

yum -y groupinstall "Development tools"
yum -y install zlib-devel bzip2-devel openssl-devel ncurses-devel sqlite-devel readline-devel tk-devel gdbm-devel db4-devel libpcap-devel xz-devel

创建Python目录

mkdir python3
cd python3/

下载Python3.7.4

wget https://www.python.org/ftp/python/3.7.4/Python-3.7.4.tar.xz

然后解压压缩包,进入该目录,安装Python3

xz -d Python-3.7.4.tar.xz 
tar xvf Python-3.7.4.tar
cd Python-3.7.4/
./configure --prefix=/python3(这里是之前我在/目录下创建了一个python3目录)
make && make install

安装成功。创建软链

ln -s /python3/bin/python3 /usr/bin/python3
ln -s /python3/bin/pip3 /usr/bin/pip3

完成

前提安装相关库

pip install mysqlclient (Windows)

import MySQLdb
import os

def CaseTable(case1):
    db = MySQLdb.connect("localhost", "root", "root", charset='utf8')#连接数据库,root分别为账号和密码
    # 使用cursor()方法获取操作游标 
    cursor = db.cursor()
    sql = "show databases"
    cursor.execute(sql)
    results = cursor.fetchall()
    re = list(results)
    #获取所选择的库中的表的数据
    case=case1
    if case == case1:
        sql = "use "+re[int(case1)][0]
        cursor.execute(sql)
        cursor.execute("show tables")
        result = cursor.fetchall()
        re1 = list(result)
        for i in range(len(list(result))):
            print(i,list(result)[i][0])
        choose = input('请选择查看哪一表中的内容:')
        #查看表中数据
        sql1 = "select * from "+re1[int(choose)][0]
        print(sql1)
        cursor.execute(sql1)
        cc = cursor.fetchall()
        for i in range(len(list(cc))):
            print(list(cc[i]))
        #更新表中password数据
        print('更新后台密码:update '+re1[int(choose)][0] +' set password=')
        print('注意:密码需要用对应的加密方式')
        password = input('')
        print('更新后台密码:update '+re1[int(choose)][0] +' set password='+password+' where id=')
        id = input('')
        update = 'update '+re1[int(choose)][0] +' set password='+password+' where id='+id
        cursor.execute(update)
        result = cursor.fetchall()
        print('更新后台密码:update '+re1[int(choose)][0] +' set password='+password+' where id='+id)
        print('更改成功')

def main():
    db = MySQLdb.connect("localhost", "root", "root", charset='utf8')
    # 使用cursor()方法获取操作游标 
    cursor = db.cursor()
    # 使用execute方法执行SQL语句
    sql = "show databases"
    cursor.execute(sql)
    #fetchall()方法获取所有返回的结果
    results = cursor.fetchall()
    re = list(results)  
    for j in range(len(re)):
        print(j ,re[j][0])
    case = input('请选择查看哪一数据库中的表')    
    CaseTable(case)
    db.close()

if __name__ == '__main__':
    main() 

​整体运行如下,脚本略水,如图所示可以更改数据,并查询所有数据库中的相关信息(缺点:只针对password数据进行快速更改)


通常我们通过普通的requests库无法爬取到js渲染后的页面
第一种方法是利用Selenium+PhantomJS结合在一起,就可以运行一个非常强大的网络爬虫,这个爬虫可以处理js,cookie,headers,以及
任何我们真实用户需要做的事情
第二种方法是利用pyppeteer(比第一种更方便些),模拟浏览器的正常请求,从而获取到任何你想要的信息
这里我记录下我学习pyppeteer和使用的一些心得:

首先就是安装问题了,由于 Pyppeteer 采用了 Python 的 async 机制,所以其运行要求的 Python 版本为 3.5 及以上。
使用pip install pyppeteer命令就能完成pyppeteer库的安装,至于chromium浏览器,只需要一条pyppeteer-install命令就会自动下载对应的最新版本chromium浏览器到pyppeteer的默认位置。
至于chromium浏览器属于谷歌浏览器的一个开发版,他们基于的是一个相同的内核,而我们的操作也是通过这个浏览器去获取爬虫所需要的所有
信息。

以下是我获取一个权重的值时遇到的上述情况,我利用pyppeteer最终获取到了目标权重值

 #success
import asyncio
from pyppeteer import launch
from pyquery import PyQuery as pq#pip install pyquery
import re
async def main():
 browser = await launch(headless=False)
 page = await browser.newPage()
 await page.setViewport({'width': 1200, 'height': 800})#设置浏览器窗体大小
 await page.goto('http://seo.chinaz.com/www.nffund.com')#访问这个网站
 page_source = await page.content()#获得这个页面内容
 text = pq(page_source)#对内容进行解析
 #baidu移动
 baiduyidong_pattern = re.compile(r'baiduapp/(.*?).gif')
 baiduyidong = baiduyidong_pattern.findall(str(text))[1]
 print(baiduyidong)
 #360权重
 san_pattern = re.compile(r'360rank/(.*?).gif')
 san = san_pattern.findall(str(text))[0]
 print(san)
 #360移动权重
 sanyidong = san_pattern.findall(str(text))[1]
 print(sanyidong)
 #神马权重
 shenma_pattern = re.compile(r'sm-waprk/(.*?).gif')
 shenma = shenma_pattern.findall(str(text))[0]
 print(shenma)
 #头条权重
 toutiao_pattern = re.compile(r'ttrank/(.*?).png')
 toutiao = toutiao_pattern.findall(str(text))[0]
 print(toutiao)
asyncio.get_event_loop().run_until_complete(main())#结尾必须加这个


更多的玩法可以参考这篇文章http://www.imooc.com/article/287325?block_id=tuijian_wz

当运行时会打开内置的chromium浏览器,当然也可以将其取消

爬虫的时候遇到封ip的时候可以采用做代理ip继续爬取,甚至可以做一个代理池,随机获取其中的代理ip,不断对目标网站继续爬取

以下是我对https://www.xicidaili.com/nn/这个国内代理网站进行爬取,这个网站中有免费的和付费的代理供我们使用

返回503,说明该网站有反爬机制

为什么会这样,是因为我们请求的太直白,python的requests库对网站请求的默认header是

很明显是一个爬虫,我们将浏览器中的header信息复制过来做成字典形式

headers的字典也可以只加User-Agent的信息

已经可以正常请求到,之后我们设置代理,(python爬虫高级用法中中自带的功能)

将代理网站获取到的ip和端口,写到字典中,但该网站

中有许多ip已经无效,请求时就会无响应,因此设置timeout延时3秒就断开

一个简单的筛选的完整代码:

import requests
from bs4 import BeautifulSoup
import re

#目标网址
for i in range(1,3238):
    url = "https://www.kuaidaili.com/free/inha/"+str(i)+"/"

    headers = {"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3",
    "Accept-Encoding": "gzip, deflate, br",
    "Accept-Language": "zh-CN,zh;q=0.9",
    "Cache-Control": "max-age=0",
    "Connection": "keep-alive",
    "Cookie": "_free_proxy_session=BAh7B0kiD3Nlc3Npb25faWQGOgZFVEkiJTBhODYzOTM2ZjNmZjVlOGVhNDEwN2IyNzdkOTJiYzZhBjsAVEkiEF9jc3JmX3Rva2VuBjsARkkiMWFzQVNrTFZzZlBweHpuajZaLy9IK1lMVXdPMUxwazRXQ3ZJcXpxWU0zMDA9BjsARg%3D%3D--3245375dab6a13de635b59428e1ab7dd714bada0; Hm_lvt_0cf76c77469e965d2957f0553e6ecf59=1578794781; Hm_lpvt_0cf76c77469e965d2957f0553e6ecf59=1578794781",
    "Host": "www.xicidaili.com",
    "User-Agent":"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36"}
    response = requests.get(url,headers = headers)
    html = response.text

    ips = re.findall('<td data-title="IP">(\d+\.\d+\.\d+\.\d+)</td>',html)
    ports = re.findall('<td data-title="PORT">(\d+)</td>',html)

    for ip in zip(ips,ports):
        proxies = {
            "http":"http://"+ip[0]+":"+ip[1],
            "https":"http://"+ip[0]+":"+ip[1],
        }
        try:
            res = requests.get('http://www.baidu.com',proxies=proxies,timeout=3)
            print(ip,"能使用")
            with open('ip.txt','a')as f:
                f.write(":".join(ip))
                f.write('\n')
        except Exception as e:
            print(ip,"不能使用")

 

这里给出几个免费的ip代理网站(目前还好使的)

http://www.66ip.cn/1.html
http://www.kuaidaili.com/free/inha/1/
http://www.xicidaili.com/nn/1
http://www.iphai.com/

然后我们利用爬取到的可用代理ip做代理池(随机获取),以下是我爬取补天公益src所有厂家域名的脚本,因为在正常的爬取中如果不加代理,一个ip爬到一定程度(大约200条左右)会被ban掉,所以利用上面的一个脚本,将获取到的可用代理做成代理池,继续爬取

这里我补充一是补天的反爬虫机制比较强,二是免费获取的代理也不够稳定(我买了付费的也不是很稳定),根据我自己测试应该要是能有稳定的代理可以爬取到

归根结底还是太菜了

import requests
import re
from bs4 import BeautifulSoup
import random
import threading
url = 'https://www.butian.net/Reward/pub'
headers={"Cookie":"登陆的cookie",
"User-Agent":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.78 Safari/537.36"}

def get_random_ip(ip_list):
    proxy_list = []
    for ip in ip_list:
        proxy_list.append('http://' + ip)
    proxy_ip = random.choice(proxy_list)
    proxies = {'http': proxy_ip}
    return proxies
    
def main():
    ip_list = open('ip.txt','r').readlines()
    proxies = get_random_ip(ip_list)
    for pnum in range(1,181):
        r=requests.post(url=url,data={'s':1,'p':pnum},proxies=proxies).json()
        for info in r["data"]["list"]:
            company_name = info["company_name"]
            #print(company_name)
            company_url = "https://www.butian.net/Loo/submit?cid="+info["company_id"]
            #print(company_url)
            html=requests.get(url=company_url,headers=headers,proxies=proxies).text
            #print(html)
            soup=BeautifulSoup(html,"lxml")        
            site = re.findall('<input class="input-xlarge" type="text" name="host" placeholder="输入所属域名或ip,若存在多个以,分隔" value="(.*)" />',html)
            # f = open('yuming.txt','a')
            # f.write(str(site[0]))
            # f.write('\n')
            print(site[0])
if __name__ == "__main__":
    main()​