Python: 盗链篇
Admin Lv3

彼窃钩者诛,窃国者为诸侯,诸侯之门而仁义存焉
——《庄子·外篇·胠箧》

盗链

盗链是一种在未经源网站主人的同意下在自己的网站上通过超链接引用其资源和服务的行为。由于这么做会让收益和名誉从贡献资源的网站主人跑到“不劳而获”的盗链者头上,此类行为被普遍认为有违道德,部分地区甚至立法禁止,但是盗链者们仍然乐此不疲的研发新盗链技术,毕竟谁能拒绝不劳而获的诱惑呢?

模拟浏览器

想要收集一个网站上的链接,首先需要创建一个浏览器对象来模拟浏览器行为,直接调用requests.get()很容易被发现是脚本

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
#!/usr/bin/env python3

import mechanize
import http.cookiejar as cookiejar
import random
import time

RED = '\033[1;31m'
GREEN = '\033[1;92m'
RESET = '\033[0m'

class Browser(mechanize.Browser):
def __init__(self, proxies=None, user_agents=None):
super().__init__()
self.set_handle_robots(False) # 不遵守robots.txt
self.proxies = proxies or []
self.user_agents = user_agents or [
'Mozilla/5.0 (Windows NT 10.0; Win64; x64)',
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7)',
'Mozilla/4.0 ',
'FireFox/6.01',
'ExactSearch',
'Nokia7110/1.0'
]
self.cookie_jar = cookiejar.LWPCookieJar() # 初始化cookie罐
self.set_cookiejar(self.cookie_jar)
self.anonymize()

def anonymize(self, sleep=False, sleep_duration=60):
"""
通过清除cookie、随机切换User-Agent头以及随机切换代理来去匿名化浏览器。
可以设置睡眠来模拟人类浏览速度。
"""
self.clear_cookies()
self.switch_user_agent()
self.switch_proxy()
if sleep:
print(f"即将睡眠{sleep_duration}秒模拟人类浏览速度")
time.sleep(sleep_duration)

def clear_cookies(self):
self.cookie_jar = cookiejar.LWPCookieJar()
self.set_cookiejar(self.cookie_jar)
print("cookie已清空")

def switch_user_agent(self):
user_agent = random.choice(self.user_agents)
self.addheaders = [('User-agent', user_agent)]
print(f"User-agent已切换为 {user_agent}")

def switch_proxy(self):
if len(self.proxies) > 0:
proxy = random.choice(self.proxies)
self.set_proxies({'http': proxy})
print(f"proxy已切换为 {proxy}")
else:
print(f"{RED}未设置proxy,切换失败{RESET}")

def fetch_html(self, url):
"""从给定的url获取html内容"""
try:
page = self.open(url)
html = page.read()
return html
except Exception as e:
print(f"{RED}{url} 获取html失败: {e}{RESET}")
return None

向同一个网站发送多次请求时可以穿插着browser.anonymize()来去实现隐匿

解析Web页面

用BeautifulSoup来去解析获取的html页面以及收集链接,简单的示例如下

1
2
3
4
5
6
7
8
9
10
11
12
...
from bs4 import BeautifulSoup
...
def collect_links(html):
links = []
soup = BeautifulSoup(html, "html.parser")
a_elems = soup.find_all(name="a")
for a_elem in a_elems:
href = a_elem.get("href")
if href:
links.append(href)
return links

可以根据需求来编写相应的收集步骤

封装

把上述功能封装成一个命令行脚本,参考如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
def main(): 
parser = argparse.ArgumentParser(description="Link grabber")
parser.add_argument("-u","--url",type=str,required=True,help="target url")
args = parser.parse_args()

browser = Browser()
html = browser.fetch_html(args.url)
if html is None:
exit(-1)
links = collect_links(html)
for link in links:
print(f"{GREEN}links{RESET}")

if __name__ == "__main__":
main()

反制

聪明的网站服务器会检查Http请求中的Referer头来去甄别该请求是否来自盗链网站。当用户点击一条链接时,浏览器会把该链接所在的网页地址放进Referer中,如果用户访问的是盗链网站,那么Referer会是盗链网站的地址

反反制

基于以上的反制手段,聪明的盗链网站并不会直接把收集到的链接放在其网页上,而是将其存储到自己的数据库里,在接收到资源请求时从数据库里找到相应的链接塞入合适的Referer自行访问到结果最后返回给用户