3

疯狂!领证还要写Python!!!

 3 years ago
source link: http://www.justdopython.com/2021/01/26/lingzheng/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

决定和女朋友去领证了,心里那个激动啊,无以言表!我们俩都是比较随性的,准备拿到户口本就去领。

可谁知女朋友回家拿户口本的时候,跟我说:最近可能领不了了!

what?到手的鸭子要飞了?我心里咯噔一下。

询问后才知道,丈母娘说领证可以,但是要选择一个良辰吉日,要求有俩:一个是看万年历,选取宜“婚假”的日子;一个是需要选择农历的双数日期,双数代表吉利。

听了之后,我拍着胸脯说没问题。接着准备去翻万年历了,可不想这时候女朋友来一句:你个呆子,还准备一天天地去翻啊?写个小程序不就1秒钟的事吗?

我拍了拍脑袋,对哦,还是老婆聪明!话不多说,打开电脑就开干。

思路和实现

我在百度输入框输入“万年历”查询,弹出的第一个当然是百度自己的万年历咯,但是我不想在百度上耗时间,因为时间紧,任务重,我选取一个相对容易的。

这个网站看起来信息比较全,并且不是那种热门的大网站,所以应该获取信息相对容易些。

首页也比较清晰明了,我所需要的几大信息(日历、农历日期、黄历)都有。

接着,我们来看看页面的请求,来定位我们所需信息的请求。

我在这个页面不算多的请求里面发现了这个请求(https://staticwnl.tianqistatic.com/Public/Home/js/api/yjs/2021.js):

这好像就是我们的目标请求,我们来看看返回:

非常好,人家一次性把一年的数据都返回了,感觉好简单啊,都不用咱们一天天请求了。

我再仔细看了下这个返回,发现并没有那么简单,我没找到农历的日期:

{
  "y": [
    "祭祀",
    "塑绘",
    "开光",
    "裁衣",
    "冠笄",
    "嫁娶",
    "纳采",
    "拆卸",
    "修造",
    "动土",
    "竖柱",
    "上梁",
    "安床",
    "移徙",
    "入宅",
    "安香",
    "结网",
    "捕捉",
    "畋猎",
    "伐木",
    "进人口",
    "放水"
  ],
  "j": [
    "出行",
    "安葬",
    "修坟",
    "开市"
  ],
  "ts": "占房床房内北",
  "c": "冲猪",
  "s": "煞东",
  "zc": "丁亥",
  "zh": "执",
  "yq": "五富 益後",
  "yj": "劫煞 小耗 复日 重日 元武"
}

我收起了天真,又开始寻找获取农历日期的方法。我没有找到获取农历日期的请求,但是我发现了一个特别的请求:

这个请求并没有直接获取农历日期,而是用 JavaScript 计算的,我们可以看到这个请求里面的计算方法:

//====================================== 算出农历, 传入日期控件, 返回农历日期控件
//                                       该控件属性有 .year .month .day .isLeap
//sDObj = new Date(y,m,i+1);   当月1日日期
function Lunar(objDate) {
    var i, leap = 0, temp = 0;
    var offset = (Date.UTC(objDate.getFullYear(), objDate.getMonth(), objDate
            .getDate()) - Date.UTC(1900, 0, 31)) / 86400000;
    for (i = 1900; i < 2100 && offset > 0; i++) {
        temp = lYearDays(i);
        offset -= temp;
    }
    if (offset < 0) {
        offset += temp;
        i--;
    }
    this.year = i;
    leap = leapMonth(i); //闰哪个月
    this.isLeap = false;
    for (i = 1; i < 13 && offset > 0; i++) {
        //闰月
        if (leap > 0 && i == (leap + 1) && this.isLeap == false) {
            --i;
            this.isLeap = true;
            temp = leapDays(this.year);
        } else {
            temp = monthDays(this.year, i);
        }
        //解除闰月
        if (this.isLeap == true && i == (leap + 1)) {
            this.isLeap = false;
        }
        offset -= temp;
    }
    if (offset == 0 && leap > 0 && i == leap + 1) {
        if (this.isLeap) {
            this.isLeap = false;
        } else {
            this.isLeap = true;
            --i;
        }
    }
    if (offset < 0) {
        offset += temp;
        --i;
    }
    this.month = i;
    this.day = offset + 1;
}

当然,这个 js 文件里面还有好多其他诸如计算星期、节假日之类的方法,我们可以把这个 js 里面的方法实现用 python 来实现就可以计算出农历日期以及节假日之类的信息了。但是我的时间比较紧迫,所以我选择用最简单的办法——百度。将度娘里面别人写的方法直接拿来用,就不用重复造轮子了。

搜索可以发现好多计算万年历信息的方法,我从其中选取了一个作为工具类来用。

前奏已经弄完了,接下来就好办了,我们来看看代码怎么写。

第一步是获取某一年每天的信息:


def get_data(year):
    url = 'https://staticwnl.tianqistatic.com/Public/Home/js/api/yjs/%d.js' % year
    response = requests.get(url)
    text = response.text
    start_str = 'lmanac["%d"] =' % year
    his_end_str = ';if(typeof(lmanac_2345)!="undefined"){lmanac_2345();}'
    cur_end_str = ';if(typeof(lmanac_2345)!="undefined"){lmanac_2345()};'
    cur_year = datetime.datetime.now().year
    jsonstr = text.replace(start_str, '')
    if cur_year == year:
        jsonstr = jsonstr.replace(cur_end_str, '')
    else:
        jsonstr = jsonstr.replace(his_end_str, '')

    return jsonstr
    

这里需要注意的是,获取到的结果数据在 JSON 数据的前后都加了字符串干扰信息,我们需要将这些字符串给去掉才能解析 JSON。

你以为这样就完了吗?是不是发现用解析2021年的数据的方法去2020年的数据不行?你没看错,这里网站开发人员开了一个小玩笑,他们把结尾字符串里面的一个分号换了个位置。据我仔细观察发现,当年的返回结果中这个分号是在最后的,而其他年份的返回数据中这个分号是在大括号里面的。

获取到数据之后,我们就来计算日期:


def choose_day(year, jsonstr):
    jobj = json.loads(jsonstr)
    for day in jobj.keys():
        y = jobj[day]['y']
        if '嫁娶' in y:
            dtime = datetime.datetime(year, int(day[1:3]), int(day[3:5]))
            # 获取农历日期
            ludar_date = lunarUtils.get_ludar_date(dtime)
            # 取得日,然后看是否是双数
            if ludar_date[2] % 2 == 0:
               print('公历日期:%s,农历日期:%s' % (day, ludar_date))

这里面就相对比较简单了,先解析返回的 JSON 数据,然后遍历日期,获取每天的信息,看哪天宜“嫁娶”,就再获取这天的农历日期,看是不是双数,如果是的话,这就是我们的目标日期。

我最后获得的日期是这样子的:

公历日期:d0107,农历日期:(2020, 11, 24)
公历日期:d0122,农历日期:(2020, 12, 10)
公历日期:d0124,农历日期:(2020, 12, 12)
公历日期:d0126,农历日期:(2020, 12, 14)
公历日期:d0203,农历日期:(2020, 12, 22)
公历日期:d0209,农历日期:(2020, 12, 28)
公历日期:d0225,农历日期:(2021, 1, 14)
公历日期:d0305,农历日期:(2021, 1, 22)
公历日期:d0311,农历日期:(2021, 1, 28)
公历日期:d0318,农历日期:(2021, 2, 6)
公历日期:d0324,农历日期:(2021, 2, 12)
公历日期:d0401,农历日期:(2021, 2, 20)
公历日期:d0419,农历日期:(2021, 3, 8)
公历日期:d0425,农历日期:(2021, 3, 14)
公历日期:d0507,农历日期:(2021, 3, 26)
公历日期:d0513,农历日期:(2021, 4, 2)
公历日期:d0525,农历日期:(2021, 4, 14)
公历日期:d0531,农历日期:(2021, 4, 20)
公历日期:d0606,农历日期:(2021, 4, 26)
公历日期:d0613,农历日期:(2021, 5, 4)
公历日期:d0617,农历日期:(2021, 5, 8)
公历日期:d0619,农历日期:(2021, 5, 10)
公历日期:d0625,农历日期:(2021, 5, 16)
公历日期:d0701,农历日期:(2021, 5, 22)
公历日期:d0711,农历日期:(2021, 6, 2)
公历日期:d0713,农历日期:(2021, 6, 4)
公历日期:d0717,农历日期:(2021, 6, 8)
公历日期:d0723,农历日期:(2021, 6, 14)
公历日期:d0725,农历日期:(2021, 6, 16)
公历日期:d0729,农历日期:(2021, 6, 20)
公历日期:d0804,农历日期:(2021, 6, 26)
公历日期:d0811,农历日期:(2021, 7, 4)
公历日期:d0813,农历日期:(2021, 7, 6)
公历日期:d0815,农历日期:(2021, 7, 8)
公历日期:d0823,农历日期:(2021, 7, 16)
公历日期:d0827,农历日期:(2021, 7, 20)
公历日期:d0914,农历日期:(2021, 8, 8)
公历日期:d0926,农历日期:(2021, 8, 20)
公历日期:d1013,农历日期:(2021, 9, 8)
公历日期:d1015,农历日期:(2021, 9, 10)
公历日期:d1025,农历日期:(2021, 9, 20)
公历日期:d1029,农历日期:(2021, 9, 24)
公历日期:d1106,农历日期:(2021, 10, 2)
公历日期:d1110,农历日期:(2021, 10, 6)
公历日期:d1112,农历日期:(2021, 10, 8)
公历日期:d1116,农历日期:(2021, 10, 12)
公历日期:d1124,农历日期:(2021, 10, 20)
公历日期:d1130,农历日期:(2021, 10, 26)
公历日期:d1207,农历日期:(2021, 11, 4)
公历日期:d1211,农历日期:(2021, 11, 8)
公历日期:d1219,农历日期:(2021, 11, 16)
公历日期:d1223,农历日期:(2021, 11, 20)
公历日期:d1231,农历日期:(2021, 11, 28)

看了一下,今天就是个好日子,公历是0126,农历是1214,12+14=26,我觉得挺好,可惜今天错过了,只能推后了。我看了一下,要赶在年前领证的话,只有两个日期可选了,我想选2月3日,这天正好立春,是个好日子。

Python 应用无处不在,只要善于运用,我们的生活会更高效美好!我马上要领证了,大家可否点个赞祝福一下?

示例代码:(https://github.com/JustDoPython/python-examples/tree/master/xianhuan/lingzheng)


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK