[개발이야기#035] 내가 해보고 싶은 것 - 자동 보팅 프로그램 하루에 한번 보팅하는 프로그램[postingcuration]

in #krlast month

안녕하세요 가야태자 @talkit 입니다.

오늘은 드디어 앞에서 작성한 프로그램을 이용해서 보팅을 시작 합니다.

user 테이블에 들어 있는 정해진 사용자와 postings 테이블에 들어 있는 최근글을 기준으로 보팅을 진행 합니다.

보팅 파워는 75%로 합니다.

관련글

[개발이야기#028] 내가 해보고 싶은 것 - 자동 보팅 프로그램 SQLite vs DuckDB [postingcuration]

[개발이야기#029] 내가 해보고 싶은 것 - 자동 보팅 프로그램 사용자 및 포스트 테이블 생성하기 [postingcuration]

[개발이야기#031] 내가 해보고 싶은 것 - 자동 보팅 프로그램 사용자 등록 프로그램 작성하기 [postingcuration]

[개발이야기#032] 내가 해보고 싶은 것 - 자동 보팅 프로그램 사용자 게시글 수집기 작성하기 [postingcuration]

[개발이야기#034] 내가 해보고 싶은 것 - 포스팅 큐레이션 글을 자동으로 정리해보자 [postingcuration]

[개발이야기#034] 내가 해보고 싶은 것 - 포스팅 큐레이션 글 목록을 자동 포스팅 하기 [postingcuration]

코드 컨셉트

이글을 실제로 10월 12일 다시 작성했습니다. 발행일은 언제가 될지 아마도 13일일 것 같습니다.

^^

원래는 75% 파워로 보팅을 해드리려고 했는데 보팅 파워에 한계가 있기도 하고,

image.png

오늘 파워업을 진행 했습니다.

그래서 스팀파워가 2000이 되었구요.

그랬더니

image.png

이게 가능하네요 ^^

그래서 보팅 파워는 50%로 결정을 했습니다.

우선은 지금 현재 #postingcuration 참여자분들께 보팅해드리고 있습니다.

소스 코드

from steem import Steem

import duckdb

from datetime import datetime, timedelta

  
  

# Steemit 계정 정보

STEEM_USERNAME = 'your_steemit_id'

STEEM_POSTING_KEY = 'your_posting_key'  # 여기에 실제 posting key를 넣어주세요

  

# Steemit 객체 생성

steem = Steem(keys=[STEEM_POSTING_KEY])

  

# DuckDB 연결 설정

conn = duckdb.connect('steemit_auto_posting.db')

  

# 로그 함수

def log(message):

    print(f"{datetime.now()} - {message}")

  

# 특정 사용자에 대한 최근 게시물 조회 함수

def fetch_recent_posts_for_voting(username, days=3):

    try:

        # 3일 이내의 게시물 조회 (글의 작성일 기준) 및 voting_status가 false인 경우만

        cutoff_date = datetime.utcnow() - timedelta(days=days)

        query = """

            SELECT post_id, title, posting_date

            FROM postings

            WHERE user_id = ? AND posting_date >= ? AND voting_status = false

            ORDER BY posting_date DESC

        """

        df = conn.execute(query, (username, cutoff_date)).fetchdf()

        return df

    except Exception as e:

        log(f"An error occurred while fetching posts for {username}: {e}")

        return None

  

# 이미 보팅했는지 확인하는 함수

def has_voted(author, permlink, voter):

    try:

        votes = steem.get_active_votes(author, permlink)

        # 해당 보팅 리스트에 계정이 있는지 확인

        return any(vote['voter'] == voter for vote in votes)

    except Exception as e:

        log(f"An error occurred while checking votes on post {author}/{permlink}: {e}")

        return False

  

# 보팅 로그 테이블에 보팅 기록 삽입

def log_voting_to_db(post_url, user_id, voting_status):

    try:

        current_time = datetime.utcnow()

        query = """

            INSERT INTO voting_logs (url, user_id, voting_status, voting_date)

            VALUES (?, ?, ?, ?)

        """

        conn.execute(query, (post_url, user_id, voting_status, current_time))

        log(f"Inserted voting record into voting_logs for post: {post_url}")

    except Exception as e:

        log(f"An error occurred while logging voting info to database: {e}")

  

# 보팅 함수

def vote_post(post_url, voter, user_id, weight=50):

    try:

        # URL에서 author와 permlink 추출

        parts = post_url.split("/")

        author = parts[-2].replace('@', '')

        permlink = parts[-1]

  

        # 이미 보팅했는지 확인

        if has_voted(author, permlink, voter):

            log(f"Already voted on post: {post_url} by {voter}")

            # 이미 보팅된 경우 voting_status를 true로, modified_at을 현재 시간으로 업데이트

            update_voting_status(post_url, True)

            # 보팅 기록 삽입

            log_voting_to_db(post_url, user_id, True)

            return

        # Steemit에 보팅

        identifier = ('@'+author+'/'+permlink)

        steem.commit.vote(identifier, float(weight), voter)

        log(f"Successfully voted on post: {post_url} by {voter}")

        # 보팅 완료 후 voting_status를 true로, modified_at을 현재 시간으로 업데이트

        update_voting_status(post_url, True)

        # 보팅 기록 삽입

        log_voting_to_db(post_url, user_id, True)

    except Exception as e:

        log(f"An error occurred while voting on post {post_url}: {e}")

        # 오류 발생 시에도 voting_status를 true로 업데이트하여 다시 시도되지 않도록 함

        update_voting_status(post_url, True)

  

# voting_status 및 modified_at 업데이트 함수

def update_voting_status(post_url, status):

    try:

        # 현재 시간을 modified_at에 설정

        current_time = datetime.utcnow()

        # voting_status 업데이트

        query = """

            UPDATE postings

            SET voting_status = ?, modified_at = ?

            WHERE post_id = ?

        """

        conn.execute(query, (status, current_time, post_url))

        log(f"Updated voting status for post: {post_url}")

    except Exception as e:

        log(f"An error occurred while updating voting status for post {post_url}: {e}")

  

# 사용자 목록 가져오기 함수 (최근 24시간 이내 보팅하지 않은 사용자만)

def get_users():

    try:

        log("Fetching active users from database")

        # 24시간 이전의 시각을 cutoff로 설정

        cutoff_date = datetime.utcnow() - timedelta(hours=24)

        # 최근 24시간 내에 voting_logs에 없는 사용자 가져오기

        query = """

            SELECT DISTINCT user_id FROM users

            WHERE is_active = 'Y'

            AND user_id NOT IN (

                SELECT DISTINCT user_id FROM voting_logs WHERE voting_date >= ?

            ) order by user_id ASC limit 1

        """

        df_users = conn.execute(query, (cutoff_date,)).fetchdf()

        return df_users['user_id'].tolist()

    except Exception as e:

        log(f"An error occurred while fetching users: {e}")

        return []

  

def main():

    # 활성화된 사용자 목록 가져오기

    users = get_users()

  

    for user in users:

        log(f"Checking posts for user {user}...")

        # 3일 이내의 게시물 가져오기

        posts_df = fetch_recent_posts_for_voting(user, days=3)

        if posts_df is not None and not posts_df.empty:

            # 최신 글의 URL 추출

            post_url = posts_df.iloc[0]['post_id']

            log(f"Found post to vote on for user {user}: {post_url}")

            # 보팅 실행

            vote_post(post_url, voter=STEEM_USERNAME, user_id=user, weight=50)

        else:

            # 현재 날짜 및 시간 가져오기

            current_time = datetime.now()

  

            # 원하는 형식으로 변환 (YYYYMMDDHH24MMII)

            formatted_time = current_time.strftime('%Y%m%d%H%M%S')

            log_voting_to_db("novoteurl_" + formatted_time, user, True)

            log(f"No recent posts to vote on for user {user}")

  

if __name__ == "__main__":

    main()

코드 설명

이 스크립트는 Steemit 플랫폼에서 특정 사용자의 최신 게시물에 자동으로 보팅을 수행하는 자동화된 과정을 제공합니다. 사용자는 DuckDB 데이터베이스를 통해 관리되며, 스크립트는 다음과 같은 주요 기능을 수행합니다:

  1. 사용자 인증 및 설정: 사용자의 스팀 계정과 개인 키를 이용하여 Steem 라이브러리를 초기화합니다.
  2. DuckDB 연결: 로컬 DuckDB 데이터베이스에 연결하여 사용자 데이터 및 게시물 정보를 저장 및 조회합니다.
  3. 최근 게시물 조회: 지정된 사용자의 최근 게시물을 조회합니다. 이때 조회 기간은 기본적으로 3일로 설정되어 있으며, 아직 보팅이 이루어지지 않은 게시물을 대상으로 합니다.
  4. 보팅 확인 및 실행: 조회된 게시물에 대해 현재 사용자가 이미 보팅을 했는지 확인하고, 보팅을 하지 않았다면 보팅을 수행합니다.
  5. 보팅 결과 로깅: 보팅의 결과와 과정을 데이터베이스에 로깅하여 추후 조회가 가능하도록 합니다.

이 과정을 통해, 스크립트는 정기적으로 특정 사용자의 게시물에 대한 지원을 자동화하고, 이에 대한 기록을 유지합니다. 스크립트는 주기적으로 실행되어 사용자의 활동을 지원하며, 이를 통해 사용자 간의 상호 작용 및 지원을 증진시키는 데 목적이 있습니다.

스크립트의 각 부분은 사용자와 관련된 데이터를 안전하게 처리하며, 모든 트랜잭션과 사용자 상호작용은 Steem 블록체인과 DuckDB 데이터베이스를 통해 관리됩니다. 이를 통해 스크립트는 효율적이고 자동화된 방식으로 Steemit 커뮤니티 내에서 활동을 지원할 수 있습니다.

실행하면 하나의 사용자만 보팅 하는 이유

        query = """

            SELECT DISTINCT user_id FROM users

            WHERE is_active = 'Y'

            AND user_id NOT IN (

                SELECT DISTINCT user_id FROM voting_logs WHERE voting_date >= ?

            ) order by user_id ASC limit 1

        """

여기 코드를 이 프로그램은 코드를 실행하면 1명의 사용자에게만 보팅을 진행 합니다.

이유는 보팅 파워 때문입니다. ^^

제가 알고 있는 지식으로 100%보팅을 하면 2%의 보팅 파워가 깍인다고 알고 있습니다.

이 2%가 98%일때 다시 100으로 복구되는 시간은 2시간입니다. ^^

그래서 저는 1시간에 1번씩 보팅을 진행하고 있습니다.

75%파워로 진행하고 있었고, 1.5%정도를 갈아 먹고 1정도의 보팅 파워가 찹니다. ^^

그래서 조금 유지되는 형태로 했고,

현재 데이터 베이스에는 21분의 사용자가 들어 있습니다.

이 사용자들에게 보팅을 하면 24시간중에 3시간 정도가 남는데 이것 때문에 60~75% 사이를 유지하고 있는 것 같습니다.

보팅 파워를 50%로 조정 했고, 조정된 보팅파워와 어느정도 되는지를 보고 보팅 시간을 30분 정도로 줄여 보려고 생각하고 있습니다.

이건 실제로 또 해보고 글로 남겨 드리겠습니다.

저도 50%로 0.01을 찍어 드리는 것은 처음이라 기대하고 있습니다.

이렇게 했을때 20분보다 더 많은 사용자들을 자동으로 보팅할 수 있을 것으로 기대 됩니다.

실행 방법

저는 이 프로그램으로 매일 매일 참가자 분들께 보팅을 해드리고 있습니다.

auto_voting_user_account2.py

코드를 복사하셔서 위 파일명으로 저장하십시오.

conda activate steemit

저를 계속 따라하셨다면 steemit 가상환경을 켜시구요.

혹시나 처음이시라면 앞에 글을 참조하시거나, 다음글에 실행 방법을 정리해보겠습니다.

python auto_voting_user_account2.py

위와 같이 실행하시면 됩니다.

결론

지금까지 열심히 자동 보팅 프로그램을 작성했습니다.

저는 자동으로 보팅을 하고 있어서 글을 쓰고 있는 지금도 ^^ 아래와 같이 보팅이 잘 되고 있습니다.

2024-10-12 21:29:52.450495 - Fetching active users from database
2024-10-12 21:29:52.832574 - Checking posts for user syskwl...
2024-10-12 21:29:52.835504 - Found post to vote on for user syskwl: https://steemit.com/kr/@syskwl/5ufbqd-1
2024-10-12 21:29:54.388941 - Successfully voted on post: https://steemit.com/kr/@syskwl/5ufbqd-1 by talkit
2024-10-12 21:29:54.390901 - Updated voting status for post: https://steemit.com/kr/@syskwl/5ufbqd-1
2024-10-12 21:29:54.392852 - Inserted voting record into voting_logs for post: https://steemit.com/kr/@syskwl/5ufbqd-1
Finished running auto_voting_user_account2.py

위 프로그램을 가지고 1시간마다 한번식 수동으로 실행하시면 ^^ 보팅이 됩니다.

그런데 사람이 하면 시간 맞추기도 힘들고 해서

다음 포스팅에 steem_schedule.py를 공개하겠습니다.

저는 저걸 이용해서 진행하고 있습니다.

리눅스 시라면 리눅스의 crontab 을 사용하셔도 됩니다.

하지만, 제 마음대로 조정할 수 있는 스케쥴러가 요즘 친해지고자하는 python에서 사용해보고 있습니다.

감사합니다.



Posted through the ECblog app (https://blog.etain.club)

Sort:  

[광고] STEEM 개발자 커뮤니티에 참여 하시면, 다양한 혜택을 받을 수 있습니다.

와~ 멋지세요!
저도 이번 큐레이팅 대회에 참여하고 계신분들께 조금이라도 보팅을 해드리고 싶은데~
어서 따라해봐야겠습니다!

고맙습니다~ ^^

^^ 저는 자고 있어도
보팅이 잘 되고 있습니다. ^^

2024-10-13 00:30:57.980587 - Fetching active users from database
2024-10-13 00:30:58.363842 - Checking posts for user yoghurty...
2024-10-13 00:30:58.367748 - Found post to vote on for user yoghurty: https://steemit.com/hive-108634/@yoghurty/m2e-2024-10-12-7-54km-4km
2024-10-13 00:31:00.163323 - Successfully voted on post: https://steemit.com/hive-108634/@yoghurty/m2e-2024-10-12-7-54km-4km by talkit
2024-10-13 00:31:00.165863 - Updated voting status for post: https://steemit.com/hive-108634/@yoghurty/m2e-2024-10-12-7-54km-4km
2024-10-13 00:31:00.167763 - Inserted voting record into voting_logs for post: https://steemit.com/hive-108634/@yoghurty/m2e-2024-10-12-7-54km-4km
Finished running auto_voting_user_account2.py

오늘 새벽에 스케쥴러가 요거트님까 보팅을 잘 했네요 ^^

모르지만 멋있습니다!

감사합니다.
@dozam 님글에도 하루에 네번째로 ^^ 보팅을 자동으로 해드리고 있네요 ^^
새로운 한주도 즐거운 한주 되시기를