多线程 爬取网页历史版本文件[源码]
本帖最后由 piazini 于 2022-1-30 20:00 编辑小技巧:启动Python默认自带的http服务器(在那个目录启动,当前路径就http服务的/根目录)
Python3:
python -m http.server 8000
Python2:
python2 -m SimpleHTTPServer
Python3 "多线程爬取历史文件"代码:
#!/usr/bin/env python3
#_*_ encoding:UTF-8 _*_
# DATE: 2022/01/20
import requests
from multiprocessing import Process,Queue
import time
import os,sys
## 文件版本
file_version = '1.0.2'
## 开始、结束日期
date_start = '0601'
date_end = '0531'
## 最大线程数。建议不超过”任务管理器--性能“里显示总数-1,
## -1是保留一个进程给其他程序用,比如显示4个,4-1=3
queue_maxsize = 2
## 全局变量
_list_month_day = []
global _flag_creat_count
_flag_creat_count = 0
global _flag_down_count
_flag_down_count = 0
## 检查设置的线程数是否超过CPU的数量
def check_cpu_count():
os_cpu_count = os.cpu_count()
if os_cpu_count < queue_maxsize:
print("\n[ Warning ] CPU支持[%d]个线程,设置线程queue_maxsize=%d,建议设置[%d],小于CPU线程数。\n"\
%(os_cpu_count,queue_maxsize,os_cpu_count-1))
## 判断date_start_month月有多少天,并设置date_start_month月的天数
def set_month_days(date_start_month):
month = date_start_month
## 是31天的月份
month_31day = "01030507081012"
## 是30天的月份
month_30day = "04060911"
## 默认是28天
day = 28
## 判断month_31day是否包含传入的month月份,为真,这月是31天
if month in month_31day:
day = 31
## 判断month_30day是否包含传入的month月份,为真,这月是30天
elif month in month_30day:
day = 30
return day
##产生月和日
def add_month_day():
date_start_month = date_start
date_start_day = date_start
## 如果月的第一位是0则取第二位
if date_start_month[:1] == "0":
date_start_month = date_start_month
## 如果日的第一位是0则取第二位
if str(date_start_day)[:1] == "0":
date_start_day = date_start_day
## 循环产生月和日
while True:
## 将上一次循环设置成int类型,转回str类型
date_start_month = str(date_start_month)
date_start_day = str(date_start_day)
## 如果日等于1号,则月份减一,
##并调用set_month_days函数,获取本月天数
if date_start_day == "1":
## 月减一
date_start_month = int(date_start_month) - 1
date_start_day = set_month_days(str(date_start_month))
else:
## 天减一
date_start_day = int(date_start_day) - 1
##month_day值:1.拼接月+日,不足两位,左补0
## 2.上面运算把月和日转成int型,拼接需要转str型
month_day = "{:0>2}".format(eval(str(date_start_month))) + "{:0>2}".format(eval(str(date_start_day)))
## 将生成的月和日添加到全局变量列表中,方便其他类或方法使用
global _list_month_day
_list_month_day.append(month_day)
## 如果当前月日和设置的date_end相等,则退出while循环
if date_end == month_day:
break
## 生成访问的url连接
def create_url(q):
global _flag_creat_count
## 调用生成日期函数
add_month_day();
## 循环生成
while True:
## 月日
for m_day in _list_month_day:
## 小时
for h in range(0,24):
## 分钟
for m in range(0,59):
## 拼接生成下载地址
# url = 'https://127.0.0.1:8000/' + file_version + '/2021' +'%s%02d%02d'%(m_day,h,m) + '/tv_' + file_version + '.apk'
url = 'http://127.0.0.1:8000/' + file_version + '/2021' +'%s%02d%02d'%(m_day,h,m) + '/tv_' + file_version + '.apk'
q.put(url)
_flag_creat_count = _flag_creat_count + 1
break
print(f"总共放入{_flag_creat_count}个URL")
return _flag_creat_count
def download_file(q):
global _flag_down_count
while True:
url = q.get()
print(f'正在连接: ' + url)
r = requests.get(url)
codes = r.status_code
## 访问网站返回值为200说明文件存在
if codes == 200:
print("找到文件: " + url )
print(">>> 记录到sucess.txt文件中")
## 参数a,追加内容到文件中
with open ('sucess.txt','a') as f:
f.write(url + '\n')
if (__name__ == 'main') or (__name__ == '__main__'):
## 记录开始时间
#t1 = time.time()
## 检查设置的线程数是否超过CPU的数量
check_cpu_count();
print("\n提示: 用Ctrl + C 结束脚本\n")
print("创建{%d}个线程..." %queue_maxsize)
q = Queue(maxsize=queue_maxsize)
c = Process(target=create_url,args=(q,))
d = Process(target=download_file,args=(q,))
d.start()
c.start()
#print("阻塞线程d")
d.join()
#print("阻塞线程c")
c.join()
## 记录结束时间
#t2 = time.time()
#print(f"总耗时:{t2 -t1}")
脚本执行效果图:
Python Http服务日志:
还有个问题,多线程脚本启动后,设定链接访问完后,也只能手动用Ctrl+C手动停止,
希望大佬赐教,应该怎么改,能让脚本访问完链接后退出。
尝试用“标记flag”和“记录产生链接数和访问链接数相等时退出”也没成功
__EOF__
好,但是不会呀 这个有用诶 有的时候想找但是又没有记录了 感谢分享,学习了 但是不会呀 ych13846701169 发表于 2022-1-30 23:48
好,但是不会呀
没关系,慢慢学:Dweeqw cxb1998 发表于 2022-1-31 00:08
这个有用诶 有的时候想找但是又没有记录了
是的,我也是因为有这个需求才写的这个 a3322a 发表于 2022-1-31 04:06
感谢分享,学习了
谢谢,互相学习 52896009 发表于 2022-1-31 12:52
但是不会呀
互相学习,慢慢来
页:
[1]