斗图啦表情包爬取

使用的模块:request,parsel,threading

项目思路

  • 确定url地址
  • 确定动静态网页
  • 确定get/post方法
  • 伪装浏览器,攻破反爬等措施

项目流程:

获取url地址

为https://www.doutula.com/

创建项目,导入模块request,parsel,threading,定义url指向需要爬取的网址,获取浏览器headers具体代码如下:

1
2
3
4
import requests,parsel,threading

url = "https://www.doutula.com/"
headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36"}

通过浏览器访问该网站发现Request Method: GET,所以使用get方法请求

1
2
response = requests.get(url,headers=headers)
print(response.text)

输出的是网站的源代码

转换数据类型

parsel模块需要安装:pip install parsel

1
2
form = parsel.Selector(response.text)
print(form)

打印的是一个selector对象,可以使用xpath表达式调用

查看网页源码发现如下代码

1
<a class="col-xs-6 col-sm3"href="https://www.doutula.com/photo/1788066"style="padding:5px;">

这个html代码是每个图片都有的父元素,而且所有的class都一样,直接采用xpath调取所有的这个元素

1
2
all_imformation = form.xpath("//a[@class='col-xs-6 col-sm-3']")
print(all_imformation)

打印多个对象

再阅读html源代码,发现img标签里是需要获得的内容

1
<img referrerpolicy="no-referrer" src="//static.doutula.com/img/loader.gif?33" style="margin: 0 auto; min-height: inherit;" data-original="http://img.doutula.com/production/uploads/image/2016/04/11/20160411380177_rJlsnS.gif" alt="手撑桌子,左看看,右看看" class="img-responsive lazy image_dta" data-backup="http://img.doutula.com/production/uploads/image/2016/04/11/20160411380177_rJlsnS.gif">

所有的标签有个共同特点,都有属性referrerpolicy=“no-referrer”,src是需要提取的图片地址这个地址有毛病,完整地址应该是data-original属性,alt是图片的名称。以此为基准继续提取

1
2
3
for i in all_imformation:
photo_name = i.xpath("./img[@referrerpolicy='no-referrer']/@alt").get()
print(photo_name)

使用到了遍历,遍历每一个对象打印出每个alt值,使用了get()函数,如果不使用打印出来的是一个对象。

然后找到地址,图片地址都有一个后缀,用split获取后缀

1
2
photo_src = i.xpath('./img[@referrerpolicy="no-referrer"]/@data-original').get()
photo_last = photo_src.split(".")[-1]

现在有了名字有了地址,下面根据地址获得二进制数据。同样都是get方法

1
2
bin_data = requests.get(photo_src,headers=headers).content
print(bin_data)

打印的是b’*'数据。

将数据写入文件,并以获取的名字命名

1
2
with open("./picture/"+photo_name+"."+photo_last,"wb") as fl:
fl.write(bin_data)

必须要在当前目录有个picture文件夹,可以用os模块创建,但是这里没有必要。要想创建步骤如下:

1
2
import os
os.mkdir("./picture")

到此整个爬取流程已经完整结束,下面需要进行页面,多线程处理。

使用多线程需要先进行封装函数,函数规划为获取页面,爬取图片内容,保存图片三个函数。对上面的程序进行函数规划。

分析url地址https://www.doutula.com/photo/list/?page=1,页数和page后面的值有关,页数随着他变化而改变。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#获取页面
def url(page):
url = "https://www.doutula.com/photo/list/?page="+str(page)
headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36"}
response = requests.get(url,headers=headers)
form = parsel.Selector(response.text)
all_imformation = form.xpath("//a[@class='col-xs-6 col-sm-3']")
get_link(all_imformation)

#爬取图片内容
def get_link(all_imformation):
for i in all_imformation:
photo_name = i.xpath('./img[@referrerpolicy="no-referrer"]/@alt').get()
photo_src = i.xpath('./img[@referrerpolicy="no-referrer"]/@data-original').get()
bin_data = requests.get(photo_src,headers=headers).content
photo_last = photo_src.split(".")[-1]
save(photo_name,photo_last,bin_data)

#保存图片
def save(photo_name,photo_last,bin_data):
with open("./picture/"+photo_name+"."+photo_last,"wb") as fl:
fl.write(bin_data)

线程处理:

定义一个main函数,用到进程

1
2
3
4
5
6
7
if __name__ =="__main__":
thread = int(input("请输入线程数:"))
li = [i for i in range(1,10)]
for i in range(1,thread):
thread=threading.Thread(target=url,args=(li[0],))
thread.start()
li.pop(0)

这个线程还是有点毛病的,输入10线程只能爬10页,没有将线程和页数分开。其实却是是这样,一个线程跑完,上面三个函数都执行一遍,线程结束。由此一个线程只能爬一页。如果想要优化只能从底层进行优化。

第一版本代码:

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
import requests,parsel,threading
#获取页面
def url(page):
url = "https://www.doutula.com/photo/list/?page="+str(page)
headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36"}
response = requests.get(url,headers=headers)
form = parsel.Selector(response.text)
all_imformation = form.xpath("//a[@class='col-xs-6 col-sm-3']")
get_link(all_imformation,headers)

#爬取图片内容
def get_link(all_imformation,headers):
for i in all_imformation:
photo_name = i.xpath('./img[@referrerpolicy="no-referrer"]/@alt').get()
photo_src = i.xpath('./img[@referrerpolicy="no-referrer"]/@data-original').get()
bin_data = requests.get(photo_src,headers=headers).content
photo_last = photo_src.split(".")[-1]
save(photo_name,photo_last,bin_data)

#保存图片
def save(photo_name,photo_last,bin_data):
with open("./picture/"+photo_name+"."+photo_last,"wb") as fl:
fl.write(bin_data)

if __name__ =="__main__":
thread = int(input("请输入线程数:"))
li = [i for i in range(1,10)]
for i in range(1,thread):
thread=threading.Thread(target=url,args=(li[0],))
thread.start()
li.pop(0)

云代理IP爬取

优化后:

为了防止竞争全局资源需要用到互斥锁

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
import requests,parsel,threading

def page(li):
lock.acquire()
if len(li)==0:
return
get_page=li[0]
li.pop(0)
lock.release()
page(li)
url(get_page)

def url(page):
print("============下载第{page}页=============".format(page=page))
url = "https://www.doutula.com/photo/list/?page="+str(page)
headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36"}
response = requests.get(url,headers=headers)
form = parsel.Selector(response.text)
all_imformation = form.xpath("//a[@class='col-xs-6 col-sm-3']")
get_link(all_imformation,headers)
print("============第{page}页下载完成=============".format(page=page))

def get_link(all_imformation,headers):
for i in all_imformation:
photo_name = i.xpath('./img[@referrerpolicy="no-referrer"]/@alt').get()
photo_src = i.xpath('./img[@referrerpolicy="no-referrer"]/@data-original').get()
bin_data = requests.get(photo_src,headers=headers).content
photo_last = photo_src.split(".")[-1]
save(photo_name,photo_last,bin_data)

def save(photo_name,photo_last,bin_data):
with open("./picture/"+photo_name+"."+photo_last,"wb") as fl:
fl.write(bin_data)

li=[]
lock = threading.Lock()
if __name__ =="__main__":
thread = int(input("请输入线程数:"))
pages = int(input("请输入需要爬取的页数:"))
li=[i for i in range(1,pages+1)]
for i in range(1,thread):
thread=threading.Thread(target=page,args=(li,))
thread.start()

不知道咋回事感觉优化后的更慢了。。。

云代理IP爬取

经过测试优化后的只是实现了页数进程分开,速度并没有之前的快。

云代理IP爬取

使用的模块:request,parsel,os

项目思路

  • 确定url地址
  • 确定动静态网页
  • 确定get/post方法
  • 伪装浏览器,攻破反爬等措施

项目流程:

获取url地址:

http://www.ip3366.net/

创建项目,导入模块request,parsel,os定义url指向需要爬取的网址,获取浏览器headers具体代码如下:

1
2
3
4
import requests,parsel,os

url = "http://www.ip3366.net/"
headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36"}

通过浏览器访问该网站发现Request Method: GET,所以使用get方法请求

1
2
response = requests.get(url,headers=headers)
print(response.text)

输出的是网站的源代码,源代码中有大量的乱码,这是由于中文编码显示导致的。查看html代码

1
<meta charset="gb2312">

发现编码是gb2312,而requests默认使用utf-8所以导致解码错误,设置requests编码为自动响应识别编码,大致意思就是自己找的charset然后设置成这个网址编码。

1
response.encoding=response.apparent_encoding

转换数据类型

parsel模块需要安装:pip install parsel

1
2
form = parsel.Selector(response.text)
print(form)

打印的是一个selector对象,可以使用xpath表达式调用

查看网页源码发现如下代码

1
2
3
4
5
6
7
8
9
10
11
12
13
<tbody>           
<tr>
<td>183.166.111.38</td>
<td>9999</td>
<td>高匿代理IP</td>
<td>HTTPS</td>
<td>GET, POST</td>
<td>安徽省淮南市</td>
<td>10秒</td>
<td>2020/7/7 11:31:18</td>
</tr>
......
</tbody>

这个html代码是所有需要爬取的内容,而且使用的table标签,直接提取标签就可以了,采用xpath调取所有的这个元素

1
2
all_tr = form.xpath("//tr")
print(all_tr)

打印多个对象

再阅读html源代码,发现第1,2,4位置的td标签里是需要获得的内容

接着上面的对象,直接提取1,2,4,注意这里需要提取的是text()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
for i in all_tr:
ip = i.xpath("./td[1]/text()").get()
port = i.xpath("./td[2]/text()").get()
method = i.xpath("./td[4]/text()").get()
print(method,ip,port)

>>>
None None None
HTTPS 182.138.238.55 9999
HTTPS 182.149.82.26 9999
HTTPS 182.149.82.27 9999
HTTPS 183.166.139.207 9999
HTTPS 182.34.37.10 9999
HTTPS 183.166.111.38 9999
HTTPS 182.34.33.191 9999
HTTPS 183.166.133.225 9999
HTTPS 182.34.37.180 9999
HTTPS 182.34.37.228 9999

使用到了遍历,遍历每一个对象,使用了get()函数,如果不使用打印出来的是一个对象。

发现第一行三个None,可能是因为xpath表达式不严谨,更改第一个xpath为:

1
all_tr = form.xpath("//tbody/tr")

将数据存储为字典格式,一个ip一个字典,不然key相等会修改字典,将这些字典添加到列表里

1
2
3
4
5
6
7
8
9
li=[]
for i in all_tr:
ip = i.xpath("./td[1]/text()").get()
port = i.xpath("./td[2]/text()").get()
method = i.xpath("./td[4]/text()").get()
dic={}
dic[method]=ip+":"+port
li.append(dic)
print(li)

获取多页数据

分析url地址规律

1
2
3
http://www.ip3366.net/?stype=1&page=1 #第一页
http://www.ip3366.net/?stype=1&page=2 #第二页
http://www.ip3366.net/?stype=1&page=3 #第三页

发现页数改变只有page后面的数字改变,根据这个规律设计爬取路线,先将前面的封装成函数,根据易读特性将函数封装为,取值函数,和收集数据函数

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
import requests,parsel,os

def get_url(page):
url = "http://www.ip3366.net/?stype=1&page="+str(page)
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36"}
response = requests.get(url,headers=headers)
response.encoding=response.apparent_encoding
form = parsel.Selector(response.text)
all_tr = form.xpath("//tbody/tr")
get_data(all_tr)

def get_data(all_tr):
li=[]
for i in all_tr:
ip = i.xpath("./td[1]/text()").get()
port = i.xpath("./td[2]/text()").get()
method = i.xpath("./td[4]/text()").get()
dic={}
dic[method]=ip+":"+port
li.append(dic)
print(li)

if __name__ == "__main__":
for i in range(1,5):
get_url(i)

大体已经出来了,但是不知道这些代理能不能用,下面设计一个验证代理可用度的函数,使用代理来访问实验室站点。将超时设置设置成1秒

1
2
3
4
def cheak(li,headers):
for i in li:
response = requests.get("https://blosslom1.github.io/",headers=headers,proxies=i,timeout=1)
print(response)

访问成功过输出<Response [200]>,但是很多情况会超时,程序就会报错所有使用try

1
2
3
4
5
6
7
8
9
10
def cheak(li,headers):
for i in li:
try:
response = requests.get("https://blosslom1.github.io/",headers=headers,proxies=i,timeout=0.1)
if response.status_code==200:
save()
except:
print(str(i)+"不通过")
else:
print(str(i)+"写入文件成功")

最后将数据写入文件,需要使用os判断文件夹是否存在,如不存在新建一个文件夹,然后创建文件写入数据。

1
2
3
4
5
6
7
def save(i):
exist_dir = os.access("./云代理",os.F_OK)
if not(exist_dir):
os.mkdir("./云代理")
with open("./云代理/IP.txt","a") as fl:
fl.write(str(i))
fl.write("\n")

项目完成代码如下:

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
import requests,parsel,os

def get_url(page):
url = "http://www.ip3366.net/?stype=1&page="+str(page)
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.142 Safari/537.36"}
response = requests.get(url,headers=headers)
response.encoding=response.apparent_encoding
form = parsel.Selector(response.text)
all_tr = form.xpath("//tbody/tr")
get_data(all_tr,headers)

def get_data(all_tr,headers):
li=[]
#headers=headers
for i in all_tr:
ip = i.xpath("./td[1]/text()").get()
port = i.xpath("./td[2]/text()").get()
method = i.xpath("./td[4]/text()").get()
dic={}
dic[method]=ip+":"+port
li.append(dic)
cheak(li,headers)

def cheak(li,headers):
for i in li:
try:
response = requests.get("https://blosslom1.github.io/",headers=headers,proxies=i,timeout=1)
if response.status_code == 200:
save(i)
except:
print(str(i)+"不通过")
else:
print(str(i)+"写入文件成功")

def save(i):
exist_dir = os.access("./云代理",os.F_OK)
if not(exist_dir):
os.mkdir("./云代理")
with open("./云代理/IP.txt","a") as fl:
fl.write(str(i))
fl.write("\n")

if __name__ == "__main__":
page = int(input("请输入页数:"))
for i in range(1,page):
get_url(i)

代理ip爬虫是非常有用的一个爬虫,我们可以使用这些爬虫爬的数据ip作为代理进行代理爬虫,爬取其他网站。我们去收集一些数据信息的就不怕封禁ip了。

云代理IP爬取

温馨提示:不要使用ip代理恶意爬取他人网站,会对他人网站造成DDoS攻击,此行为属于违法行为

DNS放大攻击

DNS放大攻击属于DDoS的一种,攻击手段类似与借刀杀人。简单来讲借用DNS服务器的数据流量对目标服务器进行攻击。DNS放大是一种反射攻击,攻击者使用伪造的源IP请求大量的DNS服务器。服务器以为查询信息是来自这些IP地址,然后将数据发送给目标,由于数量众多而且倍数放大。攻击者将自身计算机的带宽放大数倍对目标进行攻击。

实验环境

Linux Debain(被攻击系统)

Linux Parrot(攻击系统)

编程语言:python

​ 日常使用网络时我们需要大量使用DNS服务器进行域名解析,每次访问一个网站就需要向DNS服务器发一个网站域名,然后DNS服务器返回一个目标的IP地址,但是如果这个方法被骇客恶意利用那么这些DNS服务器就成为了攻击他人设备的凶器。

ping扫描

详细项目地址

源码如下

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
from scapy.all import *
import ipaddress
import logging
import random
import threading
import sys
import time

logging.getLogger("scapy.runtime").setLevel(logging.ERROR)

def ping(ip):

ip_id = random.randint(0,65535)
icmp_id = random.randint(0,65535)
seq = random.randint(0,65535)

ping = IP(dst=ip,id=ip_id)/ICMP(id=icmp_id,seq=seq)/b"who are you"
response = sr1(ping,verbose=0,timeout=2)
if response != None:
print("{ip} 存活".format(ip=ip))


if __name__=="__main__":
print(" //^^^^^^))")
print(" // ))")
print(" //======))")
print(" // ")
print(" // ")
print("// ——Blosslom")
try:
get_ip = sys.argv[1]
all_ip = ipaddress.ip_network(get_ip)
print("正在扫描"+str(all_ip)+"网段")
for ip in all_ip:
thread = threading.Thread(target=ping,args=(str(ip),))
thread.start()
except:
print("输入错误请检查输入")
print("网段需要类似192.168.0.0/24以0结尾")
time.sleep(1)
print("进程退出")

ARP局域网发现

详细项目地址

源码如下

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
from scapy.all import *
import ipaddress
import logging
import random
import threading
import sys
import time
import socket

logging.getLogger("scapy.runtime").setLevel(logging.ERROR)

def arp(ip):
arp = Ether(dst="FF:FF:FF:FF:FF:FF")/ARP(pdst=ip)/b"who are you"
response = srp1(arp,verbose=0,timeout=1)
if response != None:
print("{ip} 存活".format(ip=ip))

def get_local_ip():
try:
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(('www.baidu.com', 80))
ip = s.getsockname()[0]
finally:
s.close()
return ip

if __name__=="__main__":
print(" /\\")
print(" // \\\\ ))")
print(" //====\\\\==】)")
print(" //- ARP -\\\\]")
print(" // \\\\")
print("// \\\\ ——Blosslom")
try:
get_ip_all = sys.argv[1]
get_ip = get_ip_all.split(".")
local_ip_all = str(get_local_ip())
local_ip = local_ip_all.split(".")
if str(get_ip[0]+get_ip[1]+get_ip[2])==str(local_ip[0]+local_ip[1]+local_ip[2]):
all_ip = ipaddress.ip_network(get_ip_all)
print("正在扫描"+str(all_ip)+"网段")
for ip in all_ip:
thread = threading.Thread(target=arp,args=(str(ip),))
thread.start()
else:
print("输入错误请输入和{local_ip_all}同网段的地址".format(local_ip_all=local_ip_all))

time.sleep(1)
print("进程退出")
except:
print("输入错误请检查输入")
print("请输入和{local_ip_all}同网段的地址".format(local_ip_all=local_ip_all))

TCP端口开放扫描

详细项目地址

源码如下

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
from scapy.all import *
import ipaddress
import logging
import random
import threading
import sys
import time
import socket

logging.getLogger("scapy.runtime").setLevel(logging.ERROR)

def tcp(ip,start_port,end_port):
ip_id = random.randint(0,65535)
tcp_seq = random.randint(0,4294967295)
tcp_sport = random.randint(0,1000)
tcp = IP(id=ip_id,dst=ip)/TCP(dport=(int(start_port),int(end_port)),seq=tcp_seq)
#tcp = [i for i in tcp]
response = [i if i[1].haslayer(TCP) and i[1].getlayer(TCP).fields['flags']==18 \
else None for i in list(filter(None,[sr1(j,verbose=0,timeout=0.1) \
for j in [k for k in tcp]]))]
response = list(filter(None,response))
if response:
for i in response:
target_ip = i[0].getlayer(IP).fields["src"]
sport=i[1].getlayer(TCP).fields['sport']
print(str(target_ip)+"端口|"+str(sport)+"|开放")
print("========================")


if __name__=="__main__":
print("===============")
print(" || ))")
print(" ||\ ==】)")
print(" TCP TCP -\\\\]")
print(" ||")
print(" || ——Blosslom")
try:
get_ip = sys.argv[1]
all_ip = ipaddress.ip_network(get_ip)
get_start_port = sys.argv[2]
get_end_port = sys.argv[3]
print("正在扫描"+str(all_ip)+"网段的"+str(get_start_port)+" to "+str(get_end_port)+"端口")
for ip in all_ip:
thread = threading.Thread(target=tcp,args=(str(ip),get_start_port,get_end_port,))
thread.start()
time.sleep(1)
print("进程退出")
print("处理数据......")
except:
print("输入错误请检查输入")
print("输入格式为 IP 起始端口 结束端口")
print("例如:tcp.py 8.8.8.0/24 1 100")