[Chia sẻ] Công cụ Python tra cứu tự động hàng loạt MST (Doanh nghiệp/Cá nhân) - Quà tặng sinh nhật diễn đàn GPE! (1 người xem)

Người dùng đang xem chủ đề này

Tôi tuân thủ nội quy khi đăng bài

doanlong49

Thành viên chính thức
Tham gia
12/7/13
Bài viết
69
Được thích
66
Chào các anh chị em trên diễn đàn GPE,

Nhân dịp sinh nhật diễn đàn GPE sắp tới, mình muốn đóng góp một chút quà nhỏ cho cộng đồng. Mình có viết một đoạn code Python hỗ trợ tra cứu tự động thông tin Mã số thuế doanh nghiệp và MST cá nhân hàng loạt từ trang https://tracuunnt.gdt.gov.vn/tcnnt/mstdn.jsp

Điểm nổi bật của công cụ này là tốc độ: 1.000 MST chỉ mất khoảng 5 - 10 phút, trả về kết quả file Excel đầy đủ thông tin (Tên, trạng thái, địa chỉ...), giúp anh chị em kế toán tiết kiệm được rất nhiều thời gian so với việc tra tay.

Vì code viết bằng Python nên cần cài đặt một số thư viện môi trường ban đầu. Để hỗ trợ các bạn chưa quen với lập trình:

  • Hỗ trợ cài đặt: Bạn nào cần dùng gấp cứ inbox trực tiếp qua diễn đàn hoặc gửi email cho mình qua địa chỉ: doanlong49@gmail.com. Mình sẽ hỗ trợ cài đặt miễn phí qua UltraView cho mọi người.
  • Chia sẻ mã nguồn: Đúng ngày sinh nhật diễn đàn, mình sẽ upload toàn bộ file code lên đây để ai muốn tự nghiên cứu hoặc phát triển thêm đều có thể tải về

du lieu.png
Ketqua.png
 
Chào các anh chị em trên diễn đàn GPE,

Nhân dịp sinh nhật diễn đàn GPE sắp tới, mình muốn đóng góp một chút quà nhỏ cho cộng đồng. Mình có viết một đoạn code Python hỗ trợ tra cứu tự động thông tin Mã số thuế doanh nghiệp và MST cá nhân hàng loạt từ trang https://tracuunnt.gdt.gov.vn/tcnnt/mstdn.jsp

Điểm nổi bật của công cụ này là tốc độ: 1.000 MST chỉ mất khoảng 5 - 10 phút, trả về kết quả file Excel đầy đủ thông tin (Tên, trạng thái, địa chỉ...), giúp anh chị em kế toán tiết kiệm được rất nhiều thời gian so với việc tra tay.

Vì code viết bằng Python nên cần cài đặt một số thư viện môi trường ban đầu. Để hỗ trợ các bạn chưa quen với lập trình:

  • Hỗ trợ cài đặt: Bạn nào cần dùng gấp cứ inbox trực tiếp qua diễn đàn hoặc gửi email cho mình qua địa chỉ: doanlong49@gmail.com. Mình sẽ hỗ trợ cài đặt miễn phí qua UltraView cho mọi người.
  • Chia sẻ mã nguồn: Đúng ngày sinh nhật diễn đàn, mình sẽ upload toàn bộ file code lên đây để ai muốn tự nghiên cứu hoặc phát triển thêm đều có thể tải về

View attachment 312080
View attachment 312081
Tôi có cài Python rồi nên oánh dấu để ít bữa thử tải về dùng xem.
 
E đã gửi email đăng ký rồi ạ
 
Em xin cám ơn anh @doanlong49 đã cài đặt và hướng dẫn tận tình. Em đã sử dụng được và rất ok. Chân thành cám ơn anh :heart:
 
1784515299300.png

Tôi không sử dụng Python ... nhưng nếu có mã nguồn Tôi keo AI phân tích ra thôi ...
 
Cảm ơn anh rất nhiều ạ, hiện tại em cũng đang tra cứu thủ công từng MST, hóng đến ngày sinh nhật diễn đàn xin file cài đặt của anh ạ ^^
 
View attachment 312109

Tôi không sử dụng Python ... nhưng nếu có mã nguồn Tôi keo AI phân tích ra thôi ...
Dạ, ban đầu mình định hỗ trợ cài đặt UltraView cho từng bạn, nhưng do số lượng các bạn nhờ hỗ trợ hiện tại khá nhiều và quỹ thời gian cá nhân của mình có hạn, mình quyết định sẽ upload toàn bộ mã nguồn lên vào cuối tuần này để mọi người chủ động tải về tìm hiểu và sử dụng sớm. Chúc diễn đàn GPE của chúng ta ngày càng phát triển!

Mình chia sẻ đoạn code này với tinh thần hỗ trợ cộng đồng làm nghề. Rất mong các bạn sử dụng nó vào mục đích tốt, giúp đỡ các thành viên khác trong công việc và tuyệt đối KHÔNG dùng mã nguồn này để thương mại hóa hoặc kiếm tiền. Hãy giữ đúng tinh thần chia sẻ vốn có của diễn đàn chúng ta.
 
Dạ, ban đầu mình định hỗ trợ cài đặt UltraView cho từng bạn, nhưng do số lượng các bạn nhờ hỗ trợ hiện tại khá nhiều và quỹ thời gian cá nhân của mình có hạn, mình quyết định sẽ upload toàn bộ mã nguồn lên vào cuối tuần này để mọi người chủ động tải về tìm hiểu và sử dụng sớm. Chúc diễn đàn GPE của chúng ta ngày càng phát triển!

Mình chia sẻ đoạn code này với tinh thần hỗ trợ cộng đồng làm nghề. Rất mong các bạn sử dụng nó vào mục đích tốt, giúp đỡ các thành viên khác trong công việc và tuyệt đối KHÔNG dùng mã nguồn này để thương mại hóa hoặc kiếm tiền. Hãy giữ đúng tinh thần chia sẻ vốn có của diễn đàn chúng ta.
Tuyệt vời bác ah. Cảm ơn bác đã chia sẻ cho ace trong group, đặc biệt là a/c/e làm kế toán
 
Do mình không có quyền sửa bài viết bài 1 nên mình đăng bài ở đây.

Hôm nay, ngày 22/07/2026, mình xin chia sẻ toàn bộ đoạn code Python tra cứu MST này đến cộng đồng Giải Pháp Excel.
Do số lượng các bạn nhờ hỗ trợ cài đặt khá nhiều và quỹ thời gian cá nhân có hạn, mình tải lên sớm để mọi người có thể chủ động tải về nghiên cứu, tùy chỉnh và sử dụng ngay.

Bước 1: Download python về cài đặt ưu tiên phiên bản 3.11 > 3.14 vì hỗ trợ đầy đủ thư viện. Link download Python Releases for Windows | Python.org. Tải bên Python Releases for Windows

Thông thường Python sẽ nằm ở: C:\Users\Ten_User\AppData\Local\Programs\Python

Hoặc nếu bạn cài cho tất cả người dùng: C:\Program Files\Python3x

Bước 2:
Tải và cài đặt Tesseract OCR (Dùng để giải Captcha)

Link download https://github.com/UB-Mannheim/tesseract/wiki

Lưu ý: Tesseract thường sẽ nằm ở: C:\Program Files\Tesseract-OCR\tesseract.exe nếu cài chỉ dùng riêng cho user C:\Users\Ten_User\AppData\Local\Programs\Tesseract-OCR\tesseract.exe

Bước 3:
Cài đặt các thư viện cần thiết của python:

Mở cửa sổ Command Prompt (CMD) trên máy tính và dán dòng lệnh sau bấm Enter:

"C:\Users\Ten_User\AppData\Local\Programs\Python\Pythonxxx\python.exe" -m pip install requests

"C:\Users\ Ten_User \AppData\Local\Programs\Python\Pythonxxx\python.exe" -m pip install pillow

"C:\Users\Ten_User\AppData\Local\Programs\Python\Pythonxxx\python.exe" -m pip install pytesseract

"C:\Users\Ten_User\AppData\Local\Programs\Python\Pythonxxx\python.exe" -m pip install beautifulsoup4

"C:\Users\Ten_User\AppData\Local\Programs\Python\Pythonxxx\python.exe" -m pip install "numpy<2.0.0"

"C:\Users\Ten_User\AppData\Local\Programs\Python\Pythonxxx\python.exe" -m pip install pandas

Trường hợp python 3.12 trở lên thì cần upgrade

"C:\Users\Ten_User\AppData\Local\Programs\Python\Pythonxxx\python.exe" -m pip install numpy –upgrade

Hoặc đổi "C:\Users\Ten_User\AppData\Local\Programs\Python\Pythonxxx\python.exe" thành C:\Program Files\Python3xxx tùy thuộc vào vị trí python bạn cài

Bước 4: Cấu hình đường dẫn Tesseract trong File Python

Mở file python Request_TCTCN_1.pyRequest_TCTCT_1.py chỉnh lại đường dẫn theo đường dẫn đã cài tesseract

pytesseract.pytesseract.tesseract_cmd = (

r"C:\Users\Ten_User\AppData\Local\Programs\Tesseract-OCR\tesseract.exe"

)

Bước 5:
Đưa dữ liệu và chạy tra cứu

Tra cứu MST cá nhân: Copy danh sách mã số thuế vào file ListTaxCodeCN_1.xlsx, sau đó chạy file Request_TCTCN_1.py.

Tra cứu MST doanh nghiệp: Copy danh sách mã số thuế vào file ListTaxCodeCT_1.xlsx, sau đó chạy file Request_TCTCT_1.py.

MẸO TĂNG TỐC (Chia nhỏ file để chạy song song):

Nếu muốn tra cứu hàng ngàn MST nhanh hơn, bạn có thể tạo nhiều cặp file. Ví dụ: ListTaxCodeCN_2.xlsx đi kèm với Request_TCTCN_2.py.

Khi đó, bạn chỉ cần mở file Python tương ứng và sửa lại tên file đầu vào/đầu ra ở các dòng cấu hình:

  • Đối với MST Cá nhân:
Python

INPUT_EXCEL = os.path.join(BASE_DIR, "ListTaxCodeCN_2.xlsx")

OUTPUT_EXCEL = os.path.join(BASE_DIR, "TaxLookupResultCN_2.xlsx")

CAPTCHA_PIC = "captchaCN_2.png"

  • Đối với MST Doanh nghiệp:
Python

INPUT_EXCEL = os.path.join(BASE_DIR, "ListTaxCodeCT_2.xlsx")

OUTPUT_EXCEL = os.path.join(BASE_DIR, "TaxLookupResultCT_2.xlsx")

CAPTCHA_PIC = "captchaCT_2.png"

Theo số chạy file chia nhỏ

LƯU Ý TỪ TÁC GIẢ


  • Đây là phiên bản mã nguồn mở cơ bản nhất dành cho các bạn yêu thích lập trình tìm hiểu và tự phát triển thêm (ví dụ: đóng gói thành file .exe chạy độc lập không cần cài môi trường Python).
  • Quy định sử dụng: Tuyệt đối KHÔNG sử dụng mã nguồn này (hoặc các phiên bản nâng cấp từ mã nguồn này) vào bất kỳ mục đích thương mại/thu phí nào. Trường hợp chia sẻ lại công khai trên các nền tảng khác, vui lòng ghi rõ nguồn từ Diễn đàn Giải Pháp Excel (GPE).
Code Python Tra Cứu MST Cá Nhân
Python:
import requests
from PIL import Image
import pytesseract
from bs4 import BeautifulSoup
import pandas as pd
import time
import os
# Thêm thư viện này để tắt các dòng cảnh báo màu đỏ phiền phức khi bypass SSL
from urllib3.exceptions import InsecureRequestWarning

# Tắt cảnh báo InsecureRequestWarning trên toàn bộ hệ thống
requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning)
# ==================================================
# Cấu hình
# ==================================================

URL = "https://tracuunnt.gdt.gov.vn/tcnnt/mstcn.jsp"
CAPTCHA_URL = "https://tracuunnt.gdt.gov.vn/tcnnt/captcha.png?uid="

pytesseract.pytesseract.tesseract_cmd = (
    r"C:\Users\Ten_User\AppData\Local\Programs\Tesseract-OCR\tesseract.exe"
)

BASE_DIR = os.path.dirname(os.path.abspath(__file__))
INPUT_EXCEL = os.path.join(BASE_DIR, "ListTaxCodeCN_1.xlsx")
OUTPUT_EXCEL = os.path.join(BASE_DIR, "TaxLookupResultCN_1.xlsx")
CAPTCHA_PIC = "captchaCN_1.png"

# ==================================================
# Tạo Session
# ==================================================

def create_session():
    session = requests.Session()
       # BỎ QUA KIỂM TRA CHỨNG CHỈ SSL CHO TOÀN BỘ SESSION
    session.verify = False
    
    session.headers.update({
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
    })
    response = session.get(URL)
    print("Khởi tạo Session Status:", response.status_code)
    return session


# ==================================================
# Download Captcha
# ==================================================

def download_captcha(session, filename=CAPTCHA_PIC):
    captcha_path = os.path.join(BASE_DIR, filename)
    print("Đang chờ 1 giây trước khi lấy captcha...")
    time.sleep(1)
    
    img = session.get(f"{CAPTCHA_URL}{int(time.time()*1000)}")
    with open(captcha_path, "wb") as f:
        f.write(img.content)
    return captcha_path


# ==================================================
# OCR Captcha
# ==================================================

def read_captcha(filename=CAPTCHA_PIC, show_image=False):
    captcha_path = os.path.join(BASE_DIR, filename)
    image = Image.open(captcha_path)

    if show_image:
        image.show()

    captcha = pytesseract.image_to_string(
        image,
        config=r'--oem 3 --psm 8 -c tessedit_char_whitelist=abcdefghijklmnopqrstuvwxyz0123456789'
    )

    captcha = captcha.lower().strip()
    return captcha


# ==================================================
# Tra cứu MST
# ==================================================

def lookup_tax(session, mst, captcha):
    payload = {
        "cm": "cm",
        "mst": mst,
        "fullname": "",
        "address": "",
        "cmt": "",
        "captcha": captcha
    }
    response = session.post(URL, data=payload)
    return response.text


# ==================================================
# Parse HTML
# ==================================================

def parse_html(html_text):
    soup = BeautifulSoup(html_text, "html.parser")
    
    # 1. Sai mã captcha
    error_p = soup.find("p", style=lambda value: value and "color:red" in value.replace(" ", ""))
    if error_p:
        text_error = error_p.get_text().strip()
        if "Vui lòng nhập đúng mã xác nhận" in text_error:
            print(" -> Web thông báo: Sai mã Captcha!")
            return [], True, False

    # Kiểm tra khu vực bảng kết quả
    result_div = soup.find("div", id="resultContainer")
    if result_div is None:
        return [], False, False

    table = result_div.find("table")
    if not table:
        return [], False, False

    # 2. Đúng captcha nhưng Không tìm thấy MST phù hợp
    table_text = table.get_text()
    if "Không tìm thấy người nộp thuế nào phù hợp" in table_text:
        print(" -> Web thông báo: Không tìm thấy người nộp thuế (MST không tồn tại)!")
        return [], False, True

    # 3. Thành công, bóc tách dữ liệu
    rows = []
    for tr in table.find_all("tr")[1:]:
        cols = tr.find_all("td")
        if len(cols) != 5:
            continue

        rows.append({
            "STT": cols[0].get_text(strip=True),
            "MST": cols[1].get_text(strip=True),
            "Tên người nộp thuế": cols[2].get_text(" ", strip=True),           
            "Cơ quan thuế": cols[3].get_text(" ", strip=True),
            "Trạng thái": cols[4].get_text(" ", strip=True)
        })

    return rows, False, False


# ==================================================
# Quy trình xử lý cho một Mã Số Thuế (Trả về cả trạng thái văn bản)
# ==================================================

def process_single_mst(session, mst, max_attempts=20):
    attempt = 0
    while attempt < max_attempts:
        attempt += 1
        print(f"   [Thử Captcha lần {attempt}/{max_attempts}]")
        
        download_captcha(session)
        captcha = read_captcha(show_image=False)
        
        if not captcha:
            print("   OCR trống, thử lại mã khác...")
            continue
            
        print(f"   OCR đọc được: '{captcha}'")

        html_response = lookup_tax(session, mst, captcha)
        rows, is_wrong_captcha, is_invalid_mst = parse_html(html_response)

        if rows:
            return rows, "Tìm thành công"
            
        if is_invalid_mst:
            return None, "Web thông báo: Không tìm thấy người nộp thuế (MST không tồn tại)!"
            
        if is_wrong_captcha:
            print("   Sai mã Captcha, đang lấy mã mới...")
            
    # Hết số lần thử mà vẫn chưa vượt qua captcha hoặc không có bảng dữ liệu
    status_msg = f"Đã thử {max_attempts} lần lỗi captcha cho MST {mst}"
    print(f"   {status_msg}. Chuyển MST tiếp theo.")
    return None, status_msg


# ==================================================
# Xuất dữ liệu bảng chi tiết kết quả tra cứu
# ==================================================

def export_result_excel(df):

    try:

        df.to_excel(
            OUTPUT_EXCEL,
            index=False,
            engine="openpyxl"
        )

        print(
            f"Đã ghi {len(df)} dòng."
        )

    except PermissionError:

        print(
            "Vui lòng đóng file Excel."
        )


# ==================================================
# Ghi ngược trạng thái vào file ListTaxCodeCN.xlsx
# ==================================================

def update_input_file_status(df):
    try:
        df.to_excel(INPUT_EXCEL, sheet_name="Sheet1", index=False, engine="openpyxl")
        print(f"-> Đã ghi nhận cột Status ngược lại file gốc: {INPUT_EXCEL}")
    except PermissionError:
        print("LỖI: Vui lòng đóng file ListTaxCodeCN.xlsx để script ghi trạng thái Status!")


# ==================================================
# Main
# ==================================================

def main():
    if not os.path.exists(INPUT_EXCEL):
        print(f"Lỗi: Không tìm thấy file {INPUT_EXCEL}!")
        return

    try:
        # Đọc trọn vẹn file đầu vào để giữ lại cấu trúc các cột ban đầu
        input_df = pd.read_excel(INPUT_EXCEL, sheet_name="Sheet1", dtype={"TaxCode": str})
        if "TaxCode" not in input_df.columns:
            print("Lỗi: Không tìm thấy cột có tên 'TaxCode'!")
            return
        
        # Tạo sẵn cột Status nếu chưa có trong file
        if "Status" not in input_df.columns:
            input_df["Status"] = ""
            
        print(f"Tìm thấy tổng cộng {len(input_df)} dòng trong file Excel cần kiểm tra.")
    except Exception as e:
        print(f"Lỗi khi đọc file Excel đầu vào: {e}")
        return

    session = create_session()
    all_rows_data = [] # List tạm chứa thông tin chi tiết bóc tách từ web
    
    # Duyệt theo Index của DataFrame đầu vào để dễ ghi ngược trạng thái từng dòng
    for idx, row in input_df.iterrows():
        mst = str(row["TaxCode"]).strip()
        
        # Bỏ qua các dòng trống (NaN) không có MST
        if not mst or mst == "nan":
            continue
            
        print(f"\n==================================================")
        print(f"TIẾN HÀNH TRA CỨU [{idx+1}/{len(input_df)}]: MST {mst}")
        print(f"==================================================")
        
        # Quy trình xử lý lấy ra cả dữ liệu (nếu có) và dòng thông báo trạng thái tương ứng
        rows, status_message = process_single_mst(session, mst, max_attempts=20)
        
        # Ghi nhận trạng thái vào cột Status tại đúng dòng hiện tại
        input_df.at[idx, "Status"] = status_message
        
        if rows:
            all_results.extend(rows) if 'all_results' in locals() else all_rows_data.extend(rows)
            print(f" -> {status_message}.")
        else:
            print(f" -> Trạng thái ghi nhận: {status_message}")

    # 1. Xuất file chứa thông tin chi tiết bóc tách thành công (TaxLookupResultCN.xlsx)
    if all_rows_data:
        print(f"\n--- Đang xuất bảng chi tiết người nộp thuế TNCN ---")
        final_detail_df = pd.DataFrame(all_rows_data)
        export_result_excel(final_detail_df)

    # 2. Ghi đè ngược toàn bộ cột Status về lại file danh sách gốc (ListTaxCodeCN.xlsx)
    print(f"\n--- Đang ghi cập nhật trạng thái về file danh sách gốc ---")
    update_input_file_status(input_df)
    
    print("\n Hoàn thành toàn bộ quy trình phối hợp tra cứu và quản lý!")

if __name__ == "__main__":
    main()

Code Python Tra Cứu MST Doanh Nghiệp
Python:
import requests
from PIL import Image
import pytesseract
from bs4 import BeautifulSoup
import pandas as pd
import time
import os
# Thêm thư viện này để tắt các dòng cảnh báo màu đỏ phiền phức khi bypass SSL
from urllib3.exceptions import InsecureRequestWarning

# Tắt cảnh báo InsecureRequestWarning trên toàn bộ hệ thống
requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning)
# ==================================================
# Cấu hình
# ==================================================

URL = "https://tracuunnt.gdt.gov.vn/tcnnt/mstdn.jsp"
CAPTCHA_URL = "https://tracuunnt.gdt.gov.vn/tcnnt/captcha.png?uid="

pytesseract.pytesseract.tesseract_cmd = (
    r"C:\Users\Ten_User\AppData\Local\Programs\Tesseract-OCR\tesseract.exe"
)

BASE_DIR = os.path.dirname(os.path.abspath(__file__))
INPUT_EXCEL = os.path.join(BASE_DIR, "ListTaxCodeCT_1.xlsx")
OUTPUT_EXCEL = os.path.join(BASE_DIR, "TaxLookupResultCT_1.xlsx")
CAPTCHA_PIC = "captchaCT_1.png"

# ==================================================
# Tạo Session
# ==================================================

def create_session():
    session = requests.Session()
    # BỎ QUA KIỂM TRA CHỨNG CHỈ SSL CHO TOÀN BỘ SESSION
    session.verify = False
    
    session.headers.update({
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
    })
    response = session.get(URL)
    print("Khởi tạo Session Status:", response.status_code)
    return session


# ==================================================
# Download Captcha
# ==================================================

def download_captcha(session, filename=CAPTCHA_PIC):
    captcha_path = os.path.join(BASE_DIR, filename)
    print("Đang chờ 1 giây trước khi lấy captcha...")
    time.sleep(1)
    
    img = session.get(f"{CAPTCHA_URL}{int(time.time()*1000)}")
    with open(captcha_path, "wb") as f:
        f.write(img.content)
    return captcha_path


# ==================================================
# OCR Captcha
# ==================================================

def read_captcha(filename=CAPTCHA_PIC, show_image=False):
    captcha_path = os.path.join(BASE_DIR, filename)
    image = Image.open(captcha_path)

    if show_image:
        image.show()

    captcha = pytesseract.image_to_string(
        image,
        config=r'--oem 3 --psm 8 -c tessedit_char_whitelist=abcdefghijklmnopqrstuvwxyz0123456789'
    )

    captcha = captcha.lower().strip()
    return captcha


# ==================================================
# Tra cứu MST
# ==================================================

def lookup_tax(session, mst, captcha):
    payload = {
        "cm": "cm",
        "mst": mst,
        "fullname": "",
        "address": "",
        "cmt": "",
        "captcha": captcha
    }

    response = session.post(URL, data=payload)
    return response.text


# ==================================================
# Parse HTML (Giữ cấu trúc 6 cột cho Tab Doanh nghiệp)
# ==================================================

def parse_html(html_text):
    soup = BeautifulSoup(html_text, "html.parser")
    
    # 1. Sai mã captcha
    error_p = soup.find("p", style=lambda value: value and "color:red" in value.replace(" ", ""))
    if error_p:
        text_error = error_p.get_text().strip()
        if "Vui lòng nhập đúng mã xác nhận" in text_error:
            print(" -> Web thông báo: Sai mã Captcha!")
            return [], True, False

    # Kiểm tra khu vực bảng kết quả
    result_div = soup.find("div", id="resultContainer")
    if result_div is None:
        return [], False, False

    table = result_div.find("table")
    if not table:
        return [], False, False

    # 2. Đúng captcha nhưng Không tìm thấy MST phù hợp
    table_text = table.get_text()
    if "Không tìm thấy người nộp thuế nào phù hợp" in table_text:
        print(" -> Web thông báo: Không tìm thấy người nộp thuế (MST không tồn tại)!")
        return [], False, True

    # 3. Thành công, bóc tách dữ liệu dạng List (Cấu trúc 6 cột đầy đủ)
    rows = []
    for tr in table.find_all("tr")[1:]:
        cols = tr.find_all("td")
        if len(cols) != 6:
            continue

        rows.append({
            "STT": cols[0].get_text(strip=True),
            "MST": cols[1].get_text(strip=True),
            "Tên người nộp thuế": cols[2].get_text(" ", strip=True),
            "Địa chỉ": cols[3].get_text(" ", strip=True),
            "Cơ quan thuế": cols[4].get_text(" ", strip=True),
            "Trạng thái": cols[5].get_text(" ", strip=True)
        })

    return rows, False, False


# ==================================================
# Quy trình xử lý cho một Mã Số Thuế
# ==================================================

def process_single_mst(session, mst, max_attempts=20):
    attempt = 0
    while attempt < max_attempts:
        attempt += 1
        print(f"   [Thử Captcha lần {attempt}/{max_attempts}]")
        
        download_captcha(session)
        captcha = read_captcha(show_image=False)
        
        if not captcha:
            print("   OCR trống, thử lại mã khác...")
            continue
            
        print(f"   OCR đọc được: '{captcha}'")

        html_response = lookup_tax(session, mst, captcha)
        rows, is_wrong_captcha, is_invalid_mst = parse_html(html_response)

        if rows:
            return rows, "Tìm thành công"
            
        if is_invalid_mst:
            return None, "Web thông báo: Không tìm thấy người nộp thuế (MST không tồn tại)!"
            
        if is_wrong_captcha:
            print("   Sai mã Captcha, đang lấy mã mới...")
            
    # Hết số lần thử mà vẫn chưa vượt qua captcha hoặc lỗi hệ thống
    status_msg = f"Đã thử {max_attempts} lần lỗi captcha cho MST {mst}"
    print(f"   {status_msg}. Chuyển MST tiếp theo.")
    return None, status_msg


# ==================================================
# Xuất dữ liệu bảng chi tiết kết quả tra cứu
# ==================================================

def export_excel(df):

    try:

        df.to_excel(
            OUTPUT_EXCEL,
            index=False,
            engine="openpyxl"
        )

        print(
            f"Đã ghi {len(df)} dòng."
        )

    except PermissionError:

        print(
            "Vui lòng đóng file Excel."
        )


# ==================================================
# Ghi ngược trạng thái vào file danh sách gốc
# ==================================================

def update_input_file_status(df):
    try:
        df.to_excel(INPUT_EXCEL, sheet_name="Sheet1", index=False, engine="openpyxl")
        print(f"-> Đã ghi nhận thành công cột Status ngược lại file danh sách gốc: {INPUT_EXCEL}")
    except PermissionError:
        print("LỖI: Vui lòng đóng file ListTaxCodeCN.xlsx để script có quyền ghi trạng thái Status!")


# ==================================================
# Main (Duyệt theo dòng DataFrame để gán chính xác trạng thái)
# ==================================================

def main():
    if not os.path.exists(INPUT_EXCEL):
        print(f"Lỗi: Không tìm thấy file {INPUT_EXCEL}!")
        return

    try:
        # Đọc dữ liệu đầu vào và ép cột TaxCode thành chuỗi (String)
        input_df = pd.read_excel(INPUT_EXCEL, sheet_name="Sheet1", dtype={"TaxCode": str})
        if "TaxCode" not in input_df.columns:
            print("Lỗi: Không tìm thấy cột có tên 'TaxCode'!")
            return
        
        # Tự động tạo cột Status nếu trong file gốc chưa có sẵn
        if "Status" not in input_df.columns:
            input_df["Status"] = ""
            
        print(f"Tìm thấy tổng cộng {len(input_df)} dòng dữ liệu trong file cần kiểm tra.")
    except Exception as e:
        print(f"Lỗi khi đọc file Excel đầu vào: {e}")
        return

    session = create_session()
    all_results = []
    
    # Duyệt tuần tự qua từng Index của DataFrame để gán Status tương ứng
    for idx, row in input_df.iterrows():
        mst = str(row["TaxCode"]).strip()
        
        # Bỏ qua dòng trống không chứa mã số thuế
        if not mst or mst == "nan":
            continue
            
        print(f"\n==================================================")
        print(f"TIẾN HÀNH TRA CỨU [{idx+1}/{len(input_df)}]: MST {mst}")
        print(f"==================================================")
        
        # Lấy đồng thời dữ liệu chi tiết (nếu thành công) và thông báo trạng thái tương ứng
        rows, status_message = process_single_mst(session, mst, max_attempts=20)
        
        # Cập nhật thông điệp trạng thái vào đúng dòng hiện hành trên RAM
        input_df.at[idx, "Status"] = status_message
        
        if rows:
            all_results.extend(rows)
            print(f" -> Kết quả: {status_message}.")
        else:
            print(f" -> Kết quả: {status_message}")

    # 1. Đóng gói xuất file chi tiết các mã tìm thành công (TaxLookupResult.xlsx)
    if all_results:
        print(f"\n--- Đang đóng gói dữ liệu chi tiết kết quả tra cứu ---")
        final_df = pd.DataFrame(all_results)
        export_excel(final_df)
    else:
        print("\nKhông bóc tách được dữ liệu chi tiết nào.")

    # 2. Ghi đè ngược lại toàn bộ DataFrame (đã cập nhật cột Status) về lại file gốc
    print(f"\n--- Đang cập nhật trạng thái về lại file danh sách gốc ---")
    update_input_file_status(input_df)
    
    print("\n Hoàn thành toàn bộ quy trình tra cứu phối hợp!")


if __name__ == "__main__":
    main()
 

File đính kèm

Do mình không có quyền sửa bài viết bài 1 nên mình đăng bài ở đây.

Hôm nay, ngày 22/07/2026, mình xin chia sẻ toàn bộ đoạn code Python tra cứu MST này đến cộng đồng Giải Pháp Excel.
Do số lượng các bạn nhờ hỗ trợ cài đặt khá nhiều và quỹ thời gian cá nhân có hạn, mình tải lên sớm để mọi người có thể chủ động tải về nghiên cứu, tùy chỉnh và sử dụng ngay.

Bước 1: Download python về cài đặt ưu tiên phiên bản 3.11 > 3.14 vì hỗ trợ đầy đủ thư viện. Link download Python Releases for Windows | Python.org. Tải bên Python Releases for Windows

Thông thường Python sẽ nằm ở: C:\Users\Ten_User\AppData\Local\Programs\Python

Hoặc nếu bạn cài cho tất cả người dùng: C:\Program Files\Python3x

Bước 2:
Tải và cài đặt Tesseract OCR (Dùng để giải Captcha)

Link download https://github.com/UB-Mannheim/tesseract/wiki

Lưu ý: Tesseract thường sẽ nằm ở: C:\Program Files\Tesseract-OCR\tesseract.exe nếu cài chỉ dùng riêng cho user C:\Users\Ten_User\AppData\Local\Programs\Tesseract-OCR\tesseract.exe

Bước 3:
Cài đặt các thư viện cần thiết của python:

Mở cửa sổ Command Prompt (CMD) trên máy tính và dán dòng lệnh sau bấm Enter:

"C:\Users\Ten_User\AppData\Local\Programs\Python\Pythonxxx\python.exe" -m pip install requests

"C:\Users\ Ten_User \AppData\Local\Programs\Python\Pythonxxx\python.exe" -m pip install pillow

"C:\Users\Ten_User\AppData\Local\Programs\Python\Pythonxxx\python.exe" -m pip install pytesseract

"C:\Users\Ten_User\AppData\Local\Programs\Python\Pythonxxx\python.exe" -m pip install beautifulsoup4

"C:\Users\Ten_User\AppData\Local\Programs\Python\Pythonxxx\python.exe" -m pip install "numpy<2.0.0"

"C:\Users\Ten_User\AppData\Local\Programs\Python\Pythonxxx\python.exe" -m pip install pandas

Trường hợp python 3.12 trở lên thì cần upgrade

"C:\Users\Ten_User\AppData\Local\Programs\Python\Pythonxxx\python.exe" -m pip install numpy –upgrade

Hoặc đổi "C:\Users\Ten_User\AppData\Local\Programs\Python\Pythonxxx\python.exe" thành C:\Program Files\Python3xxx tùy thuộc vào vị trí python bạn cài

Bước 4: Cấu hình đường dẫn Tesseract trong File Python

Mở file python Request_TCTCN_1.pyRequest_TCTCT_1.py chỉnh lại đường dẫn theo đường dẫn đã cài tesseract

pytesseract.pytesseract.tesseract_cmd = (

r"C:\Users\Ten_User\AppData\Local\Programs\Tesseract-OCR\tesseract.exe"

)

Bước 5:
Đưa dữ liệu và chạy tra cứu

Tra cứu MST cá nhân: Copy danh sách mã số thuế vào file ListTaxCodeCN_1.xlsx, sau đó chạy file Request_TCTCN_1.py.

Tra cứu MST doanh nghiệp: Copy danh sách mã số thuế vào file ListTaxCodeCT_1.xlsx, sau đó chạy file Request_TCTCT_1.py.

MẸO TĂNG TỐC (Chia nhỏ file để chạy song song):

Nếu muốn tra cứu hàng ngàn MST nhanh hơn, bạn có thể tạo nhiều cặp file. Ví dụ: ListTaxCodeCN_2.xlsx đi kèm với Request_TCTCN_2.py.

Khi đó, bạn chỉ cần mở file Python tương ứng và sửa lại tên file đầu vào/đầu ra ở các dòng cấu hình:

  • Đối với MST Cá nhân:
Python

INPUT_EXCEL = os.path.join(BASE_DIR, "ListTaxCodeCN_2.xlsx")

OUTPUT_EXCEL = os.path.join(BASE_DIR, "TaxLookupResultCN_2.xlsx")

CAPTCHA_PIC = "captchaCN_2.png"

  • Đối với MST Doanh nghiệp:
Python

INPUT_EXCEL = os.path.join(BASE_DIR, "ListTaxCodeCT_2.xlsx")

OUTPUT_EXCEL = os.path.join(BASE_DIR, "TaxLookupResultCT_2.xlsx")

CAPTCHA_PIC = "captchaCT_2.png"

Theo số chạy file chia nhỏ

LƯU Ý TỪ TÁC GIẢ


  • Đây là phiên bản mã nguồn mở cơ bản nhất dành cho các bạn yêu thích lập trình tìm hiểu và tự phát triển thêm (ví dụ: đóng gói thành file .exe chạy độc lập không cần cài môi trường Python).
  • Quy định sử dụng: Tuyệt đối KHÔNG sử dụng mã nguồn này (hoặc các phiên bản nâng cấp từ mã nguồn này) vào bất kỳ mục đích thương mại/thu phí nào. Trường hợp chia sẻ lại công khai trên các nền tảng khác, vui lòng ghi rõ nguồn từ Diễn đàn Giải Pháp Excel (GPE).
Code Python Tra Cứu MST Cá Nhân
Python:
import requests
from PIL import Image
import pytesseract
from bs4 import BeautifulSoup
import pandas as pd
import time
import os
# Thêm thư viện này để tắt các dòng cảnh báo màu đỏ phiền phức khi bypass SSL
from urllib3.exceptions import InsecureRequestWarning

# Tắt cảnh báo InsecureRequestWarning trên toàn bộ hệ thống
requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning)
# ==================================================
# Cấu hình
# ==================================================

URL = "https://tracuunnt.gdt.gov.vn/tcnnt/mstcn.jsp"
CAPTCHA_URL = "https://tracuunnt.gdt.gov.vn/tcnnt/captcha.png?uid="

pytesseract.pytesseract.tesseract_cmd = (
    r"C:\Users\Ten_User\AppData\Local\Programs\Tesseract-OCR\tesseract.exe"
)

BASE_DIR = os.path.dirname(os.path.abspath(__file__))
INPUT_EXCEL = os.path.join(BASE_DIR, "ListTaxCodeCN_1.xlsx")
OUTPUT_EXCEL = os.path.join(BASE_DIR, "TaxLookupResultCN_1.xlsx")
CAPTCHA_PIC = "captchaCN_1.png"

# ==================================================
# Tạo Session
# ==================================================

def create_session():
    session = requests.Session()
       # BỎ QUA KIỂM TRA CHỨNG CHỈ SSL CHO TOÀN BỘ SESSION
    session.verify = False
  
    session.headers.update({
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
    })
    response = session.get(URL)
    print("Khởi tạo Session Status:", response.status_code)
    return session


# ==================================================
# Download Captcha
# ==================================================

def download_captcha(session, filename=CAPTCHA_PIC):
    captcha_path = os.path.join(BASE_DIR, filename)
    print("Đang chờ 1 giây trước khi lấy captcha...")
    time.sleep(1)
  
    img = session.get(f"{CAPTCHA_URL}{int(time.time()*1000)}")
    with open(captcha_path, "wb") as f:
        f.write(img.content)
    return captcha_path


# ==================================================
# OCR Captcha
# ==================================================

def read_captcha(filename=CAPTCHA_PIC, show_image=False):
    captcha_path = os.path.join(BASE_DIR, filename)
    image = Image.open(captcha_path)

    if show_image:
        image.show()

    captcha = pytesseract.image_to_string(
        image,
        config=r'--oem 3 --psm 8 -c tessedit_char_whitelist=abcdefghijklmnopqrstuvwxyz0123456789'
    )

    captcha = captcha.lower().strip()
    return captcha


# ==================================================
# Tra cứu MST
# ==================================================

def lookup_tax(session, mst, captcha):
    payload = {
        "cm": "cm",
        "mst": mst,
        "fullname": "",
        "address": "",
        "cmt": "",
        "captcha": captcha
    }
    response = session.post(URL, data=payload)
    return response.text


# ==================================================
# Parse HTML
# ==================================================

def parse_html(html_text):
    soup = BeautifulSoup(html_text, "html.parser")
  
    # 1. Sai mã captcha
    error_p = soup.find("p", style=lambda value: value and "color:red" in value.replace(" ", ""))
    if error_p:
        text_error = error_p.get_text().strip()
        if "Vui lòng nhập đúng mã xác nhận" in text_error:
            print(" -> Web thông báo: Sai mã Captcha!")
            return [], True, False

    # Kiểm tra khu vực bảng kết quả
    result_div = soup.find("div", id="resultContainer")
    if result_div is None:
        return [], False, False

    table = result_div.find("table")
    if not table:
        return [], False, False

    # 2. Đúng captcha nhưng Không tìm thấy MST phù hợp
    table_text = table.get_text()
    if "Không tìm thấy người nộp thuế nào phù hợp" in table_text:
        print(" -> Web thông báo: Không tìm thấy người nộp thuế (MST không tồn tại)!")
        return [], False, True

    # 3. Thành công, bóc tách dữ liệu
    rows = []
    for tr in table.find_all("tr")[1:]:
        cols = tr.find_all("td")
        if len(cols) != 5:
            continue

        rows.append({
            "STT": cols[0].get_text(strip=True),
            "MST": cols[1].get_text(strip=True),
            "Tên người nộp thuế": cols[2].get_text(" ", strip=True),         
            "Cơ quan thuế": cols[3].get_text(" ", strip=True),
            "Trạng thái": cols[4].get_text(" ", strip=True)
        })

    return rows, False, False


# ==================================================
# Quy trình xử lý cho một Mã Số Thuế (Trả về cả trạng thái văn bản)
# ==================================================

def process_single_mst(session, mst, max_attempts=20):
    attempt = 0
    while attempt < max_attempts:
        attempt += 1
        print(f"   [Thử Captcha lần {attempt}/{max_attempts}]")
      
        download_captcha(session)
        captcha = read_captcha(show_image=False)
      
        if not captcha:
            print("   OCR trống, thử lại mã khác...")
            continue
          
        print(f"   OCR đọc được: '{captcha}'")

        html_response = lookup_tax(session, mst, captcha)
        rows, is_wrong_captcha, is_invalid_mst = parse_html(html_response)

        if rows:
            return rows, "Tìm thành công"
          
        if is_invalid_mst:
            return None, "Web thông báo: Không tìm thấy người nộp thuế (MST không tồn tại)!"
          
        if is_wrong_captcha:
            print("   Sai mã Captcha, đang lấy mã mới...")
          
    # Hết số lần thử mà vẫn chưa vượt qua captcha hoặc không có bảng dữ liệu
    status_msg = f"Đã thử {max_attempts} lần lỗi captcha cho MST {mst}"
    print(f"   {status_msg}. Chuyển MST tiếp theo.")
    return None, status_msg


# ==================================================
# Xuất dữ liệu bảng chi tiết kết quả tra cứu
# ==================================================

def export_result_excel(df):

    try:

        df.to_excel(
            OUTPUT_EXCEL,
            index=False,
            engine="openpyxl"
        )

        print(
            f"Đã ghi {len(df)} dòng."
        )

    except PermissionError:

        print(
            "Vui lòng đóng file Excel."
        )


# ==================================================
# Ghi ngược trạng thái vào file ListTaxCodeCN.xlsx
# ==================================================

def update_input_file_status(df):
    try:
        df.to_excel(INPUT_EXCEL, sheet_name="Sheet1", index=False, engine="openpyxl")
        print(f"-> Đã ghi nhận cột Status ngược lại file gốc: {INPUT_EXCEL}")
    except PermissionError:
        print("LỖI: Vui lòng đóng file ListTaxCodeCN.xlsx để script ghi trạng thái Status!")


# ==================================================
# Main
# ==================================================

def main():
    if not os.path.exists(INPUT_EXCEL):
        print(f"Lỗi: Không tìm thấy file {INPUT_EXCEL}!")
        return

    try:
        # Đọc trọn vẹn file đầu vào để giữ lại cấu trúc các cột ban đầu
        input_df = pd.read_excel(INPUT_EXCEL, sheet_name="Sheet1", dtype={"TaxCode": str})
        if "TaxCode" not in input_df.columns:
            print("Lỗi: Không tìm thấy cột có tên 'TaxCode'!")
            return
      
        # Tạo sẵn cột Status nếu chưa có trong file
        if "Status" not in input_df.columns:
            input_df["Status"] = ""
          
        print(f"Tìm thấy tổng cộng {len(input_df)} dòng trong file Excel cần kiểm tra.")
    except Exception as e:
        print(f"Lỗi khi đọc file Excel đầu vào: {e}")
        return

    session = create_session()
    all_rows_data = [] # List tạm chứa thông tin chi tiết bóc tách từ web
  
    # Duyệt theo Index của DataFrame đầu vào để dễ ghi ngược trạng thái từng dòng
    for idx, row in input_df.iterrows():
        mst = str(row["TaxCode"]).strip()
      
        # Bỏ qua các dòng trống (NaN) không có MST
        if not mst or mst == "nan":
            continue
          
        print(f"\n==================================================")
        print(f"TIẾN HÀNH TRA CỨU [{idx+1}/{len(input_df)}]: MST {mst}")
        print(f"==================================================")
      
        # Quy trình xử lý lấy ra cả dữ liệu (nếu có) và dòng thông báo trạng thái tương ứng
        rows, status_message = process_single_mst(session, mst, max_attempts=20)
      
        # Ghi nhận trạng thái vào cột Status tại đúng dòng hiện tại
        input_df.at[idx, "Status"] = status_message
      
        if rows:
            all_results.extend(rows) if 'all_results' in locals() else all_rows_data.extend(rows)
            print(f" -> {status_message}.")
        else:
            print(f" -> Trạng thái ghi nhận: {status_message}")

    # 1. Xuất file chứa thông tin chi tiết bóc tách thành công (TaxLookupResultCN.xlsx)
    if all_rows_data:
        print(f"\n--- Đang xuất bảng chi tiết người nộp thuế TNCN ---")
        final_detail_df = pd.DataFrame(all_rows_data)
        export_result_excel(final_detail_df)

    # 2. Ghi đè ngược toàn bộ cột Status về lại file danh sách gốc (ListTaxCodeCN.xlsx)
    print(f"\n--- Đang ghi cập nhật trạng thái về file danh sách gốc ---")
    update_input_file_status(input_df)
  
    print("\n Hoàn thành toàn bộ quy trình phối hợp tra cứu và quản lý!")

if __name__ == "__main__":
    main()

Code Python Tra Cứu MST Doanh Nghiệp
Python:
import requests
from PIL import Image
import pytesseract
from bs4 import BeautifulSoup
import pandas as pd
import time
import os
# Thêm thư viện này để tắt các dòng cảnh báo màu đỏ phiền phức khi bypass SSL
from urllib3.exceptions import InsecureRequestWarning

# Tắt cảnh báo InsecureRequestWarning trên toàn bộ hệ thống
requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning)
# ==================================================
# Cấu hình
# ==================================================

URL = "https://tracuunnt.gdt.gov.vn/tcnnt/mstdn.jsp"
CAPTCHA_URL = "https://tracuunnt.gdt.gov.vn/tcnnt/captcha.png?uid="

pytesseract.pytesseract.tesseract_cmd = (
    r"C:\Users\Ten_User\AppData\Local\Programs\Tesseract-OCR\tesseract.exe"
)

BASE_DIR = os.path.dirname(os.path.abspath(__file__))
INPUT_EXCEL = os.path.join(BASE_DIR, "ListTaxCodeCT_1.xlsx")
OUTPUT_EXCEL = os.path.join(BASE_DIR, "TaxLookupResultCT_1.xlsx")
CAPTCHA_PIC = "captchaCT_1.png"

# ==================================================
# Tạo Session
# ==================================================

def create_session():
    session = requests.Session()
    # BỎ QUA KIỂM TRA CHỨNG CHỈ SSL CHO TOÀN BỘ SESSION
    session.verify = False
  
    session.headers.update({
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
    })
    response = session.get(URL)
    print("Khởi tạo Session Status:", response.status_code)
    return session


# ==================================================
# Download Captcha
# ==================================================

def download_captcha(session, filename=CAPTCHA_PIC):
    captcha_path = os.path.join(BASE_DIR, filename)
    print("Đang chờ 1 giây trước khi lấy captcha...")
    time.sleep(1)
  
    img = session.get(f"{CAPTCHA_URL}{int(time.time()*1000)}")
    with open(captcha_path, "wb") as f:
        f.write(img.content)
    return captcha_path


# ==================================================
# OCR Captcha
# ==================================================

def read_captcha(filename=CAPTCHA_PIC, show_image=False):
    captcha_path = os.path.join(BASE_DIR, filename)
    image = Image.open(captcha_path)

    if show_image:
        image.show()

    captcha = pytesseract.image_to_string(
        image,
        config=r'--oem 3 --psm 8 -c tessedit_char_whitelist=abcdefghijklmnopqrstuvwxyz0123456789'
    )

    captcha = captcha.lower().strip()
    return captcha


# ==================================================
# Tra cứu MST
# ==================================================

def lookup_tax(session, mst, captcha):
    payload = {
        "cm": "cm",
        "mst": mst,
        "fullname": "",
        "address": "",
        "cmt": "",
        "captcha": captcha
    }

    response = session.post(URL, data=payload)
    return response.text


# ==================================================
# Parse HTML (Giữ cấu trúc 6 cột cho Tab Doanh nghiệp)
# ==================================================

def parse_html(html_text):
    soup = BeautifulSoup(html_text, "html.parser")
  
    # 1. Sai mã captcha
    error_p = soup.find("p", style=lambda value: value and "color:red" in value.replace(" ", ""))
    if error_p:
        text_error = error_p.get_text().strip()
        if "Vui lòng nhập đúng mã xác nhận" in text_error:
            print(" -> Web thông báo: Sai mã Captcha!")
            return [], True, False

    # Kiểm tra khu vực bảng kết quả
    result_div = soup.find("div", id="resultContainer")
    if result_div is None:
        return [], False, False

    table = result_div.find("table")
    if not table:
        return [], False, False

    # 2. Đúng captcha nhưng Không tìm thấy MST phù hợp
    table_text = table.get_text()
    if "Không tìm thấy người nộp thuế nào phù hợp" in table_text:
        print(" -> Web thông báo: Không tìm thấy người nộp thuế (MST không tồn tại)!")
        return [], False, True

    # 3. Thành công, bóc tách dữ liệu dạng List (Cấu trúc 6 cột đầy đủ)
    rows = []
    for tr in table.find_all("tr")[1:]:
        cols = tr.find_all("td")
        if len(cols) != 6:
            continue

        rows.append({
            "STT": cols[0].get_text(strip=True),
            "MST": cols[1].get_text(strip=True),
            "Tên người nộp thuế": cols[2].get_text(" ", strip=True),
            "Địa chỉ": cols[3].get_text(" ", strip=True),
            "Cơ quan thuế": cols[4].get_text(" ", strip=True),
            "Trạng thái": cols[5].get_text(" ", strip=True)
        })

    return rows, False, False


# ==================================================
# Quy trình xử lý cho một Mã Số Thuế
# ==================================================

def process_single_mst(session, mst, max_attempts=20):
    attempt = 0
    while attempt < max_attempts:
        attempt += 1
        print(f"   [Thử Captcha lần {attempt}/{max_attempts}]")
      
        download_captcha(session)
        captcha = read_captcha(show_image=False)
      
        if not captcha:
            print("   OCR trống, thử lại mã khác...")
            continue
          
        print(f"   OCR đọc được: '{captcha}'")

        html_response = lookup_tax(session, mst, captcha)
        rows, is_wrong_captcha, is_invalid_mst = parse_html(html_response)

        if rows:
            return rows, "Tìm thành công"
          
        if is_invalid_mst:
            return None, "Web thông báo: Không tìm thấy người nộp thuế (MST không tồn tại)!"
          
        if is_wrong_captcha:
            print("   Sai mã Captcha, đang lấy mã mới...")
          
    # Hết số lần thử mà vẫn chưa vượt qua captcha hoặc lỗi hệ thống
    status_msg = f"Đã thử {max_attempts} lần lỗi captcha cho MST {mst}"
    print(f"   {status_msg}. Chuyển MST tiếp theo.")
    return None, status_msg


# ==================================================
# Xuất dữ liệu bảng chi tiết kết quả tra cứu
# ==================================================

def export_excel(df):

    try:

        df.to_excel(
            OUTPUT_EXCEL,
            index=False,
            engine="openpyxl"
        )

        print(
            f"Đã ghi {len(df)} dòng."
        )

    except PermissionError:

        print(
            "Vui lòng đóng file Excel."
        )


# ==================================================
# Ghi ngược trạng thái vào file danh sách gốc
# ==================================================

def update_input_file_status(df):
    try:
        df.to_excel(INPUT_EXCEL, sheet_name="Sheet1", index=False, engine="openpyxl")
        print(f"-> Đã ghi nhận thành công cột Status ngược lại file danh sách gốc: {INPUT_EXCEL}")
    except PermissionError:
        print("LỖI: Vui lòng đóng file ListTaxCodeCN.xlsx để script có quyền ghi trạng thái Status!")


# ==================================================
# Main (Duyệt theo dòng DataFrame để gán chính xác trạng thái)
# ==================================================

def main():
    if not os.path.exists(INPUT_EXCEL):
        print(f"Lỗi: Không tìm thấy file {INPUT_EXCEL}!")
        return

    try:
        # Đọc dữ liệu đầu vào và ép cột TaxCode thành chuỗi (String)
        input_df = pd.read_excel(INPUT_EXCEL, sheet_name="Sheet1", dtype={"TaxCode": str})
        if "TaxCode" not in input_df.columns:
            print("Lỗi: Không tìm thấy cột có tên 'TaxCode'!")
            return
      
        # Tự động tạo cột Status nếu trong file gốc chưa có sẵn
        if "Status" not in input_df.columns:
            input_df["Status"] = ""
          
        print(f"Tìm thấy tổng cộng {len(input_df)} dòng dữ liệu trong file cần kiểm tra.")
    except Exception as e:
        print(f"Lỗi khi đọc file Excel đầu vào: {e}")
        return

    session = create_session()
    all_results = []
  
    # Duyệt tuần tự qua từng Index của DataFrame để gán Status tương ứng
    for idx, row in input_df.iterrows():
        mst = str(row["TaxCode"]).strip()
      
        # Bỏ qua dòng trống không chứa mã số thuế
        if not mst or mst == "nan":
            continue
          
        print(f"\n==================================================")
        print(f"TIẾN HÀNH TRA CỨU [{idx+1}/{len(input_df)}]: MST {mst}")
        print(f"==================================================")
      
        # Lấy đồng thời dữ liệu chi tiết (nếu thành công) và thông báo trạng thái tương ứng
        rows, status_message = process_single_mst(session, mst, max_attempts=20)
      
        # Cập nhật thông điệp trạng thái vào đúng dòng hiện hành trên RAM
        input_df.at[idx, "Status"] = status_message
      
        if rows:
            all_results.extend(rows)
            print(f" -> Kết quả: {status_message}.")
        else:
            print(f" -> Kết quả: {status_message}")

    # 1. Đóng gói xuất file chi tiết các mã tìm thành công (TaxLookupResult.xlsx)
    if all_results:
        print(f"\n--- Đang đóng gói dữ liệu chi tiết kết quả tra cứu ---")
        final_df = pd.DataFrame(all_results)
        export_excel(final_df)
    else:
        print("\nKhông bóc tách được dữ liệu chi tiết nào.")

    # 2. Ghi đè ngược lại toàn bộ DataFrame (đã cập nhật cột Status) về lại file gốc
    print(f"\n--- Đang cập nhật trạng thái về lại file danh sách gốc ---")
    update_input_file_status(input_df)
  
    print("\n Hoàn thành toàn bộ quy trình tra cứu phối hợp!")


if __name__ == "__main__":
    main()
Em đã dựng và chạy thử thành công, cảm ơn anh đã chỉ dẫn chi tiết tận tình.
Trước đây em đã từng sử dụng Tesseract-OCR để gắp nộp dung trong mấy file PDF, mà em chưa nghĩ tới vụ giải mã capcha như anh, hôm nay em đã học hỏi được thêm. Xin cảm ơn.!
 
Cám ơn tác giả rất nhiều để không cần cài thêm Tesseract-OCR\tesseract.exe mình đã text thử python314; và các thư viện ddddocr; pandas; openpyxl sau đó biên dịch ra file .exe là chạy tốt.
Lần nữa cám ơn tác giả đã đầu tư công, sức vật lộn với một loạt code để chia sẽ anh em nghiên cứu.
 
Do mình không có quyền sửa bài viết bài 1 nên mình đăng bài ở đây.

Hôm nay, ngày 22/07/2026, mình xin chia sẻ toàn bộ đoạn code Python tra cứu MST này đến cộng đồng Giải Pháp Excel.
Do số lượng các bạn nhờ hỗ trợ cài đặt khá nhiều và quỹ thời gian cá nhân có hạn, mình tải lên sớm để mọi người có thể chủ động tải về nghiên cứu, tùy chỉnh và sử dụng ngay.

Bước 1: Download python về cài đặt ưu tiên phiên bản 3.11 > 3.14 vì hỗ trợ đầy đủ thư viện. Link download Python Releases for Windows | Python.org. Tải bên Python Releases for Windows

Thông thường Python sẽ nằm ở: C:\Users\Ten_User\AppData\Local\Programs\Python

Hoặc nếu bạn cài cho tất cả người dùng: C:\Program Files\Python3x

Bước 2:
Tải và cài đặt Tesseract OCR (Dùng để giải Captcha)

Link download https://github.com/UB-Mannheim/tesseract/wiki

Lưu ý: Tesseract thường sẽ nằm ở: C:\Program Files\Tesseract-OCR\tesseract.exe nếu cài chỉ dùng riêng cho user C:\Users\Ten_User\AppData\Local\Programs\Tesseract-OCR\tesseract.exe

Bước 3:
Cài đặt các thư viện cần thiết của python:

Mở cửa sổ Command Prompt (CMD) trên máy tính và dán dòng lệnh sau bấm Enter:

"C:\Users\Ten_User\AppData\Local\Programs\Python\Pythonxxx\python.exe" -m pip install requests

"C:\Users\ Ten_User \AppData\Local\Programs\Python\Pythonxxx\python.exe" -m pip install pillow

"C:\Users\Ten_User\AppData\Local\Programs\Python\Pythonxxx\python.exe" -m pip install pytesseract

"C:\Users\Ten_User\AppData\Local\Programs\Python\Pythonxxx\python.exe" -m pip install beautifulsoup4

"C:\Users\Ten_User\AppData\Local\Programs\Python\Pythonxxx\python.exe" -m pip install "numpy<2.0.0"

"C:\Users\Ten_User\AppData\Local\Programs\Python\Pythonxxx\python.exe" -m pip install pandas

Trường hợp python 3.12 trở lên thì cần upgrade

"C:\Users\Ten_User\AppData\Local\Programs\Python\Pythonxxx\python.exe" -m pip install numpy –upgrade

Hoặc đổi "C:\Users\Ten_User\AppData\Local\Programs\Python\Pythonxxx\python.exe" thành C:\Program Files\Python3xxx tùy thuộc vào vị trí python bạn cài

Bước 4: Cấu hình đường dẫn Tesseract trong File Python

Mở file python Request_TCTCN_1.pyRequest_TCTCT_1.py chỉnh lại đường dẫn theo đường dẫn đã cài tesseract

pytesseract.pytesseract.tesseract_cmd = (

r"C:\Users\Ten_User\AppData\Local\Programs\Tesseract-OCR\tesseract.exe"

)

Bước 5:
Đưa dữ liệu và chạy tra cứu

Tra cứu MST cá nhân: Copy danh sách mã số thuế vào file ListTaxCodeCN_1.xlsx, sau đó chạy file Request_TCTCN_1.py.

Tra cứu MST doanh nghiệp: Copy danh sách mã số thuế vào file ListTaxCodeCT_1.xlsx, sau đó chạy file Request_TCTCT_1.py.

MẸO TĂNG TỐC (Chia nhỏ file để chạy song song):

Nếu muốn tra cứu hàng ngàn MST nhanh hơn, bạn có thể tạo nhiều cặp file. Ví dụ: ListTaxCodeCN_2.xlsx đi kèm với Request_TCTCN_2.py.

Khi đó, bạn chỉ cần mở file Python tương ứng và sửa lại tên file đầu vào/đầu ra ở các dòng cấu hình:

  • Đối với MST Cá nhân:
Python

INPUT_EXCEL = os.path.join(BASE_DIR, "ListTaxCodeCN_2.xlsx")

OUTPUT_EXCEL = os.path.join(BASE_DIR, "TaxLookupResultCN_2.xlsx")

CAPTCHA_PIC = "captchaCN_2.png"

  • Đối với MST Doanh nghiệp:
Python

INPUT_EXCEL = os.path.join(BASE_DIR, "ListTaxCodeCT_2.xlsx")

OUTPUT_EXCEL = os.path.join(BASE_DIR, "TaxLookupResultCT_2.xlsx")

CAPTCHA_PIC = "captchaCT_2.png"

Theo số chạy file chia nhỏ

LƯU Ý TỪ TÁC GIẢ


  • Đây là phiên bản mã nguồn mở cơ bản nhất dành cho các bạn yêu thích lập trình tìm hiểu và tự phát triển thêm (ví dụ: đóng gói thành file .exe chạy độc lập không cần cài môi trường Python).
  • Quy định sử dụng: Tuyệt đối KHÔNG sử dụng mã nguồn này (hoặc các phiên bản nâng cấp từ mã nguồn này) vào bất kỳ mục đích thương mại/thu phí nào. Trường hợp chia sẻ lại công khai trên các nền tảng khác, vui lòng ghi rõ nguồn từ Diễn đàn Giải Pháp Excel (GPE).
Code Python Tra Cứu MST Cá Nhân
Python:
import requests
from PIL import Image
import pytesseract
from bs4 import BeautifulSoup
import pandas as pd
import time
import os
# Thêm thư viện này để tắt các dòng cảnh báo màu đỏ phiền phức khi bypass SSL
from urllib3.exceptions import InsecureRequestWarning

# Tắt cảnh báo InsecureRequestWarning trên toàn bộ hệ thống
requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning)
# ==================================================
# Cấu hình
# ==================================================

URL = "https://tracuunnt.gdt.gov.vn/tcnnt/mstcn.jsp"
CAPTCHA_URL = "https://tracuunnt.gdt.gov.vn/tcnnt/captcha.png?uid="

pytesseract.pytesseract.tesseract_cmd = (
    r"C:\Users\Ten_User\AppData\Local\Programs\Tesseract-OCR\tesseract.exe"
)

BASE_DIR = os.path.dirname(os.path.abspath(__file__))
INPUT_EXCEL = os.path.join(BASE_DIR, "ListTaxCodeCN_1.xlsx")
OUTPUT_EXCEL = os.path.join(BASE_DIR, "TaxLookupResultCN_1.xlsx")
CAPTCHA_PIC = "captchaCN_1.png"

# ==================================================
# Tạo Session
# ==================================================

def create_session():
    session = requests.Session()
       # BỎ QUA KIỂM TRA CHỨNG CHỈ SSL CHO TOÀN BỘ SESSION
    session.verify = False
   
    session.headers.update({
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
    })
    response = session.get(URL)
    print("Khởi tạo Session Status:", response.status_code)
    return session


# ==================================================
# Download Captcha
# ==================================================

def download_captcha(session, filename=CAPTCHA_PIC):
    captcha_path = os.path.join(BASE_DIR, filename)
    print("Đang chờ 1 giây trước khi lấy captcha...")
    time.sleep(1)
   
    img = session.get(f"{CAPTCHA_URL}{int(time.time()*1000)}")
    with open(captcha_path, "wb") as f:
        f.write(img.content)
    return captcha_path


# ==================================================
# OCR Captcha
# ==================================================

def read_captcha(filename=CAPTCHA_PIC, show_image=False):
    captcha_path = os.path.join(BASE_DIR, filename)
    image = Image.open(captcha_path)

    if show_image:
        image.show()

    captcha = pytesseract.image_to_string(
        image,
        config=r'--oem 3 --psm 8 -c tessedit_char_whitelist=abcdefghijklmnopqrstuvwxyz0123456789'
    )

    captcha = captcha.lower().strip()
    return captcha


# ==================================================
# Tra cứu MST
# ==================================================

def lookup_tax(session, mst, captcha):
    payload = {
        "cm": "cm",
        "mst": mst,
        "fullname": "",
        "address": "",
        "cmt": "",
        "captcha": captcha
    }
    response = session.post(URL, data=payload)
    return response.text


# ==================================================
# Parse HTML
# ==================================================

def parse_html(html_text):
    soup = BeautifulSoup(html_text, "html.parser")
   
    # 1. Sai mã captcha
    error_p = soup.find("p", style=lambda value: value and "color:red" in value.replace(" ", ""))
    if error_p:
        text_error = error_p.get_text().strip()
        if "Vui lòng nhập đúng mã xác nhận" in text_error:
            print(" -> Web thông báo: Sai mã Captcha!")
            return [], True, False

    # Kiểm tra khu vực bảng kết quả
    result_div = soup.find("div", id="resultContainer")
    if result_div is None:
        return [], False, False

    table = result_div.find("table")
    if not table:
        return [], False, False

    # 2. Đúng captcha nhưng Không tìm thấy MST phù hợp
    table_text = table.get_text()
    if "Không tìm thấy người nộp thuế nào phù hợp" in table_text:
        print(" -> Web thông báo: Không tìm thấy người nộp thuế (MST không tồn tại)!")
        return [], False, True

    # 3. Thành công, bóc tách dữ liệu
    rows = []
    for tr in table.find_all("tr")[1:]:
        cols = tr.find_all("td")
        if len(cols) != 5:
            continue

        rows.append({
            "STT": cols[0].get_text(strip=True),
            "MST": cols[1].get_text(strip=True),
            "Tên người nộp thuế": cols[2].get_text(" ", strip=True),          
            "Cơ quan thuế": cols[3].get_text(" ", strip=True),
            "Trạng thái": cols[4].get_text(" ", strip=True)
        })

    return rows, False, False


# ==================================================
# Quy trình xử lý cho một Mã Số Thuế (Trả về cả trạng thái văn bản)
# ==================================================

def process_single_mst(session, mst, max_attempts=20):
    attempt = 0
    while attempt < max_attempts:
        attempt += 1
        print(f"   [Thử Captcha lần {attempt}/{max_attempts}]")
       
        download_captcha(session)
        captcha = read_captcha(show_image=False)
       
        if not captcha:
            print("   OCR trống, thử lại mã khác...")
            continue
           
        print(f"   OCR đọc được: '{captcha}'")

        html_response = lookup_tax(session, mst, captcha)
        rows, is_wrong_captcha, is_invalid_mst = parse_html(html_response)

        if rows:
            return rows, "Tìm thành công"
           
        if is_invalid_mst:
            return None, "Web thông báo: Không tìm thấy người nộp thuế (MST không tồn tại)!"
           
        if is_wrong_captcha:
            print("   Sai mã Captcha, đang lấy mã mới...")
           
    # Hết số lần thử mà vẫn chưa vượt qua captcha hoặc không có bảng dữ liệu
    status_msg = f"Đã thử {max_attempts} lần lỗi captcha cho MST {mst}"
    print(f"   {status_msg}. Chuyển MST tiếp theo.")
    return None, status_msg


# ==================================================
# Xuất dữ liệu bảng chi tiết kết quả tra cứu
# ==================================================

def export_result_excel(df):

    try:

        df.to_excel(
            OUTPUT_EXCEL,
            index=False,
            engine="openpyxl"
        )

        print(
            f"Đã ghi {len(df)} dòng."
        )

    except PermissionError:

        print(
            "Vui lòng đóng file Excel."
        )


# ==================================================
# Ghi ngược trạng thái vào file ListTaxCodeCN.xlsx
# ==================================================

def update_input_file_status(df):
    try:
        df.to_excel(INPUT_EXCEL, sheet_name="Sheet1", index=False, engine="openpyxl")
        print(f"-> Đã ghi nhận cột Status ngược lại file gốc: {INPUT_EXCEL}")
    except PermissionError:
        print("LỖI: Vui lòng đóng file ListTaxCodeCN.xlsx để script ghi trạng thái Status!")


# ==================================================
# Main
# ==================================================

def main():
    if not os.path.exists(INPUT_EXCEL):
        print(f"Lỗi: Không tìm thấy file {INPUT_EXCEL}!")
        return

    try:
        # Đọc trọn vẹn file đầu vào để giữ lại cấu trúc các cột ban đầu
        input_df = pd.read_excel(INPUT_EXCEL, sheet_name="Sheet1", dtype={"TaxCode": str})
        if "TaxCode" not in input_df.columns:
            print("Lỗi: Không tìm thấy cột có tên 'TaxCode'!")
            return
       
        # Tạo sẵn cột Status nếu chưa có trong file
        if "Status" not in input_df.columns:
            input_df["Status"] = ""
           
        print(f"Tìm thấy tổng cộng {len(input_df)} dòng trong file Excel cần kiểm tra.")
    except Exception as e:
        print(f"Lỗi khi đọc file Excel đầu vào: {e}")
        return

    session = create_session()
    all_rows_data = [] # List tạm chứa thông tin chi tiết bóc tách từ web
   
    # Duyệt theo Index của DataFrame đầu vào để dễ ghi ngược trạng thái từng dòng
    for idx, row in input_df.iterrows():
        mst = str(row["TaxCode"]).strip()
       
        # Bỏ qua các dòng trống (NaN) không có MST
        if not mst or mst == "nan":
            continue
           
        print(f"\n==================================================")
        print(f"TIẾN HÀNH TRA CỨU [{idx+1}/{len(input_df)}]: MST {mst}")
        print(f"==================================================")
       
        # Quy trình xử lý lấy ra cả dữ liệu (nếu có) và dòng thông báo trạng thái tương ứng
        rows, status_message = process_single_mst(session, mst, max_attempts=20)
       
        # Ghi nhận trạng thái vào cột Status tại đúng dòng hiện tại
        input_df.at[idx, "Status"] = status_message
       
        if rows:
            all_results.extend(rows) if 'all_results' in locals() else all_rows_data.extend(rows)
            print(f" -> {status_message}.")
        else:
            print(f" -> Trạng thái ghi nhận: {status_message}")

    # 1. Xuất file chứa thông tin chi tiết bóc tách thành công (TaxLookupResultCN.xlsx)
    if all_rows_data:
        print(f"\n--- Đang xuất bảng chi tiết người nộp thuế TNCN ---")
        final_detail_df = pd.DataFrame(all_rows_data)
        export_result_excel(final_detail_df)

    # 2. Ghi đè ngược toàn bộ cột Status về lại file danh sách gốc (ListTaxCodeCN.xlsx)
    print(f"\n--- Đang ghi cập nhật trạng thái về file danh sách gốc ---")
    update_input_file_status(input_df)
   
    print("\n Hoàn thành toàn bộ quy trình phối hợp tra cứu và quản lý!")

if __name__ == "__main__":
    main()

Code Python Tra Cứu MST Doanh Nghiệp
Python:
import requests
from PIL import Image
import pytesseract
from bs4 import BeautifulSoup
import pandas as pd
import time
import os
# Thêm thư viện này để tắt các dòng cảnh báo màu đỏ phiền phức khi bypass SSL
from urllib3.exceptions import InsecureRequestWarning

# Tắt cảnh báo InsecureRequestWarning trên toàn bộ hệ thống
requests.packages.urllib3.disable_warnings(category=InsecureRequestWarning)
# ==================================================
# Cấu hình
# ==================================================

URL = "https://tracuunnt.gdt.gov.vn/tcnnt/mstdn.jsp"
CAPTCHA_URL = "https://tracuunnt.gdt.gov.vn/tcnnt/captcha.png?uid="

pytesseract.pytesseract.tesseract_cmd = (
    r"C:\Users\Ten_User\AppData\Local\Programs\Tesseract-OCR\tesseract.exe"
)

BASE_DIR = os.path.dirname(os.path.abspath(__file__))
INPUT_EXCEL = os.path.join(BASE_DIR, "ListTaxCodeCT_1.xlsx")
OUTPUT_EXCEL = os.path.join(BASE_DIR, "TaxLookupResultCT_1.xlsx")
CAPTCHA_PIC = "captchaCT_1.png"

# ==================================================
# Tạo Session
# ==================================================

def create_session():
    session = requests.Session()
    # BỎ QUA KIỂM TRA CHỨNG CHỈ SSL CHO TOÀN BỘ SESSION
    session.verify = False
   
    session.headers.update({
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
    })
    response = session.get(URL)
    print("Khởi tạo Session Status:", response.status_code)
    return session


# ==================================================
# Download Captcha
# ==================================================

def download_captcha(session, filename=CAPTCHA_PIC):
    captcha_path = os.path.join(BASE_DIR, filename)
    print("Đang chờ 1 giây trước khi lấy captcha...")
    time.sleep(1)
   
    img = session.get(f"{CAPTCHA_URL}{int(time.time()*1000)}")
    with open(captcha_path, "wb") as f:
        f.write(img.content)
    return captcha_path


# ==================================================
# OCR Captcha
# ==================================================

def read_captcha(filename=CAPTCHA_PIC, show_image=False):
    captcha_path = os.path.join(BASE_DIR, filename)
    image = Image.open(captcha_path)

    if show_image:
        image.show()

    captcha = pytesseract.image_to_string(
        image,
        config=r'--oem 3 --psm 8 -c tessedit_char_whitelist=abcdefghijklmnopqrstuvwxyz0123456789'
    )

    captcha = captcha.lower().strip()
    return captcha


# ==================================================
# Tra cứu MST
# ==================================================

def lookup_tax(session, mst, captcha):
    payload = {
        "cm": "cm",
        "mst": mst,
        "fullname": "",
        "address": "",
        "cmt": "",
        "captcha": captcha
    }

    response = session.post(URL, data=payload)
    return response.text


# ==================================================
# Parse HTML (Giữ cấu trúc 6 cột cho Tab Doanh nghiệp)
# ==================================================

def parse_html(html_text):
    soup = BeautifulSoup(html_text, "html.parser")
   
    # 1. Sai mã captcha
    error_p = soup.find("p", style=lambda value: value and "color:red" in value.replace(" ", ""))
    if error_p:
        text_error = error_p.get_text().strip()
        if "Vui lòng nhập đúng mã xác nhận" in text_error:
            print(" -> Web thông báo: Sai mã Captcha!")
            return [], True, False

    # Kiểm tra khu vực bảng kết quả
    result_div = soup.find("div", id="resultContainer")
    if result_div is None:
        return [], False, False

    table = result_div.find("table")
    if not table:
        return [], False, False

    # 2. Đúng captcha nhưng Không tìm thấy MST phù hợp
    table_text = table.get_text()
    if "Không tìm thấy người nộp thuế nào phù hợp" in table_text:
        print(" -> Web thông báo: Không tìm thấy người nộp thuế (MST không tồn tại)!")
        return [], False, True

    # 3. Thành công, bóc tách dữ liệu dạng List (Cấu trúc 6 cột đầy đủ)
    rows = []
    for tr in table.find_all("tr")[1:]:
        cols = tr.find_all("td")
        if len(cols) != 6:
            continue

        rows.append({
            "STT": cols[0].get_text(strip=True),
            "MST": cols[1].get_text(strip=True),
            "Tên người nộp thuế": cols[2].get_text(" ", strip=True),
            "Địa chỉ": cols[3].get_text(" ", strip=True),
            "Cơ quan thuế": cols[4].get_text(" ", strip=True),
            "Trạng thái": cols[5].get_text(" ", strip=True)
        })

    return rows, False, False


# ==================================================
# Quy trình xử lý cho một Mã Số Thuế
# ==================================================

def process_single_mst(session, mst, max_attempts=20):
    attempt = 0
    while attempt < max_attempts:
        attempt += 1
        print(f"   [Thử Captcha lần {attempt}/{max_attempts}]")
       
        download_captcha(session)
        captcha = read_captcha(show_image=False)
       
        if not captcha:
            print("   OCR trống, thử lại mã khác...")
            continue
           
        print(f"   OCR đọc được: '{captcha}'")

        html_response = lookup_tax(session, mst, captcha)
        rows, is_wrong_captcha, is_invalid_mst = parse_html(html_response)

        if rows:
            return rows, "Tìm thành công"
           
        if is_invalid_mst:
            return None, "Web thông báo: Không tìm thấy người nộp thuế (MST không tồn tại)!"
           
        if is_wrong_captcha:
            print("   Sai mã Captcha, đang lấy mã mới...")
           
    # Hết số lần thử mà vẫn chưa vượt qua captcha hoặc lỗi hệ thống
    status_msg = f"Đã thử {max_attempts} lần lỗi captcha cho MST {mst}"
    print(f"   {status_msg}. Chuyển MST tiếp theo.")
    return None, status_msg


# ==================================================
# Xuất dữ liệu bảng chi tiết kết quả tra cứu
# ==================================================

def export_excel(df):

    try:

        df.to_excel(
            OUTPUT_EXCEL,
            index=False,
            engine="openpyxl"
        )

        print(
            f"Đã ghi {len(df)} dòng."
        )

    except PermissionError:

        print(
            "Vui lòng đóng file Excel."
        )


# ==================================================
# Ghi ngược trạng thái vào file danh sách gốc
# ==================================================

def update_input_file_status(df):
    try:
        df.to_excel(INPUT_EXCEL, sheet_name="Sheet1", index=False, engine="openpyxl")
        print(f"-> Đã ghi nhận thành công cột Status ngược lại file danh sách gốc: {INPUT_EXCEL}")
    except PermissionError:
        print("LỖI: Vui lòng đóng file ListTaxCodeCN.xlsx để script có quyền ghi trạng thái Status!")


# ==================================================
# Main (Duyệt theo dòng DataFrame để gán chính xác trạng thái)
# ==================================================

def main():
    if not os.path.exists(INPUT_EXCEL):
        print(f"Lỗi: Không tìm thấy file {INPUT_EXCEL}!")
        return

    try:
        # Đọc dữ liệu đầu vào và ép cột TaxCode thành chuỗi (String)
        input_df = pd.read_excel(INPUT_EXCEL, sheet_name="Sheet1", dtype={"TaxCode": str})
        if "TaxCode" not in input_df.columns:
            print("Lỗi: Không tìm thấy cột có tên 'TaxCode'!")
            return
       
        # Tự động tạo cột Status nếu trong file gốc chưa có sẵn
        if "Status" not in input_df.columns:
            input_df["Status"] = ""
           
        print(f"Tìm thấy tổng cộng {len(input_df)} dòng dữ liệu trong file cần kiểm tra.")
    except Exception as e:
        print(f"Lỗi khi đọc file Excel đầu vào: {e}")
        return

    session = create_session()
    all_results = []
   
    # Duyệt tuần tự qua từng Index của DataFrame để gán Status tương ứng
    for idx, row in input_df.iterrows():
        mst = str(row["TaxCode"]).strip()
       
        # Bỏ qua dòng trống không chứa mã số thuế
        if not mst or mst == "nan":
            continue
           
        print(f"\n==================================================")
        print(f"TIẾN HÀNH TRA CỨU [{idx+1}/{len(input_df)}]: MST {mst}")
        print(f"==================================================")
       
        # Lấy đồng thời dữ liệu chi tiết (nếu thành công) và thông báo trạng thái tương ứng
        rows, status_message = process_single_mst(session, mst, max_attempts=20)
       
        # Cập nhật thông điệp trạng thái vào đúng dòng hiện hành trên RAM
        input_df.at[idx, "Status"] = status_message
       
        if rows:
            all_results.extend(rows)
            print(f" -> Kết quả: {status_message}.")
        else:
            print(f" -> Kết quả: {status_message}")

    # 1. Đóng gói xuất file chi tiết các mã tìm thành công (TaxLookupResult.xlsx)
    if all_results:
        print(f"\n--- Đang đóng gói dữ liệu chi tiết kết quả tra cứu ---")
        final_df = pd.DataFrame(all_results)
        export_excel(final_df)
    else:
        print("\nKhông bóc tách được dữ liệu chi tiết nào.")

    # 2. Ghi đè ngược lại toàn bộ DataFrame (đã cập nhật cột Status) về lại file gốc
    print(f"\n--- Đang cập nhật trạng thái về lại file danh sách gốc ---")
    update_input_file_status(input_df)
   
    print("\n Hoàn thành toàn bộ quy trình tra cứu phối hợp!")


if __name__ == "__main__":
    main()
Công đức vô lượng!!! Xin chân thành cảm ơn bác doanlong49 rất nhiều ! Chúc bác doanlong49 thật nhiều sức khỏe, nhiều niềm vui, luôn luôn gặp may mắn, thành công, hạnh phúc, bình an !
 
mình bị kẹt ở bước mở file Request_TCTCN ạ, mn giúp mình với
Bài đã được tự động gộp:

Screenshot 2026-07-22 200531.png
Em đang bị như thế này, em có thể khắc phục bằng cách nào ạ
 
Lần chỉnh sửa cuối:
Món này chuẩn phải train được captcha để gặp nó tự giải, hoặc AI để cho nó gõ
 
dính tới file "C:\Users\Ten_User\AppData\Local\Programs\Tesseract-OCR\tesseract.exe"

link sau ...

xem ra cũng mệt mõi :p nếu không cài nó thì ai đó có thể xin file này xong thử trên ngôn ngữ khác xem sao


Thử xem, thư viện này viết bằng C nên có sẵn header rồi, ngoài ra còn thấy thư viện gói gọn dành cho một vài ngôn ngữ khác.
 
Trong lúc chờ tác giả chia sẻ code các bác có thể ngâm cứu code này trên github coi có dùng được món gì không nhé! https://github.com/luckycloudyoursky/tracuunnt1
Tôi mới test sơ sơ 100 cái hình captcha thì thấy cái thư viện ddddocr này (đọc 1 lần) nó giải đúng 99% (sai cái hình số 89) đó bạn (có thể cái captcha của trang tracuunnt nó ít phức tạp). Test số lượng nhiều thì chưa có điều kiện để thử xem tỷ lệ giải đúng bao nhiêu % :D.
Mà cái ddddocr này với thư viện onnx runtime chỉ hỗ trợ được tới Python 13 (Mac os) thôi. Bản cao hơn không cài được nhe.

Screenshot 2026-07-23 at 12.30.43 AM.png
 
Lần chỉnh sửa cuối:
Thử xem, thư viện này viết bằng C nên có sẵn header rồi, ngoài ra còn thấy thư viện gói gọn dành cho một vài ngôn ngữ khác.
1/ hai file .py ở bài số 18 thì viết trên Ngôn ngữ nào trả được ... có lẽ tôi sẽ viết C++ Builder

2/ còn xem nguồn tesseract.exe trên Github nó khung khiếp quá có chăng chỉ xem một vài cái xem là cái gì thôi

3/ link sau nó không xuất một Exe duy nhất là có lý do của nó ... suy đoán thôi nó dựa vào nguồn đó tuỳ chỉnh lại chút ít gì đó + kèm theo nhiều DLL khác nữa xong nó đóng gói vào một file cài đặt vì vậy có xin tesseract.exe của ai đó copy sang máy sạch sử dụng chắc chắn cũng tịt


4/ ai đã từng sử dụng thành công Copy qua máy sạch không cài py và các thư viện liên quan cho ý kiến xem sao xong tính tiếp ???!!!
 
1/ hai file .py ở bài số 18 thì viết trên Ngôn ngữ nào trả được ... có lẽ tôi sẽ viết C++ Builder

2/ còn xem nguồn tesseract.exe trên Github nó khung khiếp quá có chăng chỉ xem một vài cái xem là cái gì thôi

3/ link sau nó không xuất một Exe duy nhất là có lý do của nó ... suy đoán thôi nó dựa vào nguồn đó tuỳ chỉnh lại chút ít gì đó + kèm theo nhiều DLL khác nữa xong nó đóng gói vào một file cài đặt vì vậy có xin tesseract.exe của ai đó copy sang máy sạch sử dụng chắc chắn cũng tịt


4/ ai đã từng sử dụng thành công Copy qua máy sạch không cài py và các thư viện liên quan cho ý kiến xem sao xong tính tiếp ???!!!
Thấy có hai dạng, một là dùng dạng .exe (không cần phải cài đặt thêm mấy cái DLL phụ thuộc), hai là dạng DLL truyền thống. Nói chung là dùng loại nào thì tùy người sử dụng.
 
Thấy có hai dạng, một là dùng dạng .exe (không cần phải cài đặt thêm mấy cái DLL phụ thuộc), hai là dạng DLL truyền thống. Nói chung là dùng loại nào thì tùy người sử dụng.
chi tiết là gì và ông có file Samples đó không úp lên đây cho mọi người thử xem

rảnh tôi viết hai file .py bài 18 trên Delphi/C++ Builder trong tầm tay rồi ... còn cái vụ cài Tools đó giải mã captra thì đang nghe ngóng xem sao xong tính

viết xong trên Delphi có thể xem xét viết trên Go vì Go cho Network quá tốt
 
chi tiết là gì và ông có file Samples đó không úp lên đây cho mọi người thử xem

rảnh tôi viết hai file .py bài 18 trên Delphi/C++ Builder trong tầm tay rồi ... còn cái vụ cài Tools đó giải mã captra thì đang nghe ngóng xem sao xong tính

viết xong trên Delphi có thể xem xét viết trên Go vì Go cho Network quá tốt
Ông biên dịch từ nguồn, chi tiết xem ở đây: Compilation guide for various platforms
Xem một số mẫu mã C++ ở đây: C++ API Examples
 
mình bị kẹt ở bước mở file Request_TCTCN ạ, mn giúp mình với
Bài đã được tự động gộp:

View attachment 312131
Em đang bị như thế này, em có thể khắc phục bằng cách nào ạ
Máy bạn đang bị thiếu thư viện openpyxl (thư viện giúp Python đọc/ghi file Excel .xlsx).

Cách khắc phục:
Bạn mở cửa sổ Command Prompt (CMD) lên và gõ lệnh sau để cài bổ sung:

py -m pip install openpyxl
Lưu ý: Nếu máy báo lỗi hoặc cài nhiều bản Python, bạn gõ đầy đủ đường dẫn tới file python.exe trên máy bạn nhé:

"C:\Users\Ten_User\AppData\Local\Programs\Python\Pythonxxx\python.exe" -m pip install openpyxl
Sau khi cài xong bạn chạy lại code là sẽ đọc được file Excel bình thường!
Bài đã được tự động gộp:

Tôi mới test sơ sơ 100 cái hình captcha thì thấy cái thư viện ddddocr này (đọc 1 lần) nó giải đúng 99% (sai cái hình số 89) đó bạn (có thể cái captcha của trang tracuunnt nó ít phức tạp). Test số lượng nhiều thì chưa có điều kiện để thử xem tỷ lệ giải đúng bao nhiêu % :D.
Mà cái ddddocr này với thư viện onnx runtime chỉ hỗ trợ được tới Python 13 (Mac os) thôi. Bản cao hơn không cài được nhe.

View attachment 312134
Em nghĩ mình chuyển sang dùng thư viện ddddocr luôn đi anh.

Dùng thư viện này cực kỳ tiện vì nó là thư viện Python thuần (pip install ddddocr), giải captcha dạng số/chữ rất tốt mà mọi người lại không cần phải tải và cài đặt thêm phần mềm Tesseract OCR phức tạp nữa. Bước cấu hình đường dẫn tesseract_cmd cũng bỏ được luôn, giúp người mới dễ sử dụng hơn rất nhiều!
Bài đã được tự động gộp:

Do quyền của tài khoản hiện tại không sửa lại được bài viết hướng dẫn ở trên, mình xin bổ sung thêm một lưu ý nhỏ cho các bạn mới cài Python lần đầu:

Trong quá trình chạy code đọc file Excel .xlsx, nếu máy báo thiếu thư viện openpyxl, các bạn mở Command Prompt (CMD) và gõ câu lệnh sau để cài bổ sung nhé:

py -m pip install openpyxl
 
Lần chỉnh sửa cuối:
thua chạy mất dép ... thong thả tôi thử nhiều cách xem sao xong tính ... có lẽ cài là chắc chắn
1784779864732.png

Tôi khuyên ông nên dùng vcpkg tích hợp vào Visual Studio, cài đặt tự động hết chỉ cần lo viết mã thôi, chứ tôi thấy nếu dùng C++ Builder thì phức tạp lắm, căn bản việc dựng từ nguồn Tesseract chỉ hỗ trợ những trình biên dịch dưới đây:

1784779810830.png
 
Thông thường đối với kế toán hiện nay, ngoài việc tra cứu thông tin thì còn có 1 nhu cầu khác là chụp ảnh màn hình lại, nhằm mục đích lưu lại bằng chứng tại thời điểm tra cứu doanh nghiệp đó vẫn còn hoạt động. Sau này khi đơn vị bên kia không may bị dính vào black list của cơ quan thuế thì công ty còn có bằng chứng để giải trình.
Dựa vào code tác giả em đã dựng 1 file .exe để tra cứu thông tin, mọi thứ chạy mượt mà, duy chỉ có muốn chụp màn hình thì phải thực hiện nhiều request tới thuế hơn, mỗi mã ngoài việc tra cứu, còn thêm cả chục request để tải logo/ảnh/CSS về hiển thị, làm cho lưu lượng tăng gấp nhiều lần. Việc này làm cho thuế block ngắn hạn địa chỉ IP, chỉ tra và chụp khoảng 2-3 mã thì ổn, chứ nhiều quá thì bị block ngay.
Có bác nào có hướng giải quyết không ạ, em mò mò từ qua tới nay mà vẫn đang bó tay.
1784781927852.png
 
... muốn chụp màn hình thì phải thực hiện nhiều request tới thuế hơn, mỗi mã ngoài việc tra cứu, còn thêm cả chục request để tải logo/ảnh/CSS về hiển thị, làm cho lưu lượng tăng gấp nhiều lần. ...
Bạn có hình mẫu không, tôi ngoài ngành nên chưa hình dung được cái hình cần chụp phải có logo, ảnh ...như thế nào, không phải là chụp thuần túy screenshot?
 
Bạn có hình mẫu không, tôi ngoài ngành nên chưa hình dung được cái hình cần chụp phải có logo, ảnh ...như thế nào, không phải là chụp thuần túy screenshot?
Anh vào link sau nha: https://tracuunnt.gdt.gov.vn/tcnnt/mstdn.jsp
Như thường lệ sau khi tra cứu 1 mã số thuế nào đó, kế toán một vài cty sẽ chụp màn hình lại, có ngày giờ máy tính để làm căn cứ xác minh tại thời điểm tra cứu doanh nghiệp đó vẫn còn hoạt động.

Nếu chỉ đơn giản là tra cứu thông tin, code hiện tại sẽ chỉ request để nhận mã capcha, giải và gửi câu trả lời, rồi chờ nhận thông tin phản hồi.
Còn nếu mở trình duyệt lên, thì ngoài request thông tin sẽ còn có các yêu cầu khác như lấy logo, file trang trí CSS/JS, lấy hình nền, nút bấm, icon... số lượng request sẽ nhiều lên và mỗi lần tải 1 mã số thuế là 1 lần request lại từ đầu tất cả, điều này làm cho sever thuế block tạm thời địa chỉ IP, theo em hiểu là vậy.
 
Lần chỉnh sửa cuối:
Thông thường đối với kế toán hiện nay, ngoài việc tra cứu thông tin thì còn có 1 nhu cầu khác là chụp ảnh màn hình lại, nhằm mục đích lưu lại bằng chứng tại thời điểm tra cứu doanh nghiệp đó vẫn còn hoạt động. Sau này khi đơn vị bên kia không may bị dính vào black list của cơ quan thuế thì công ty còn có bằng chứng để giải trình.
Dựa vào code tác giả em đã dựng 1 file .exe để tra cứu thông tin, mọi thứ chạy mượt mà, duy chỉ có muốn chụp màn hình thì phải thực hiện nhiều request tới thuế hơn, mỗi mã ngoài việc tra cứu, còn thêm cả chục request để tải logo/ảnh/CSS về hiển thị, làm cho lưu lượng tăng gấp nhiều lần. Việc này làm cho thuế block ngắn hạn địa chỉ IP, chỉ tra và chụp khoảng 2-3 mã thì ổn, chứ nhiều quá thì bị block ngay.
Có bác nào có hướng giải quyết không ạ, em mò mò từ qua tới nay mà vẫn đang bó tay.
View attachment 312140
Làm giao diện nhìn chuyên nghiệp không thua gì phần mềm bán tiền luôn bạn ơi! Cảm ơn đóng góp rất tuyệt vời của bạn cho diễn đàn. Anh em cứ dùng thoải mái và cùng giữ đúng tinh thần phi thương mại nhé!
Nếu nhu cầu chính của bạn là chụp màn hình làm bằng chứng lưu trữ, mình khuyên bạn nên kết hợp hoặc chuyển sang dùng Power Automate Desktop (PAD) cho tác vụ này.

Lý do PAD giải quyết được bài toán này:
  1. Tránh bị block IP: PAD điều khiển trực tiếp trình duyệt thật (Edge/Chrome) thông qua giao diện người dùng (UI), tải trang và giữ session giống hệt thao tác của kế toán thật nên không tạo ra dồn dập các request bất thường như khi chạy bằng Python/Crawler.
  2. Tự động chụp & lưu file dễ dàng: PAD có sẵn các hành động (Actions) rất mạnh về Take Screenshot hoặc Print to PDF, tự động đặt tên file theo MST + Ngày tháng và lưu thẳng vào thư mục máy tính/OneDrive rất mượt mà.
  3. Miễn phí & Có sẵn: PAD tích hợp sẵn trên Windows 11 (hoặc tải miễn phí trên Windows 10), cực kỳ phù hợp cho dân kế toán sử dụng mà không cần cấu hình phức tạp.
Còn giải pháp Python hiện tại, bạn nên để nó tập trung cho nhiệm vụ tra cứu dữ liệu hàng loạt ra file Excel (nhẹ, nhanh, quét được số lượng lớn). Khi cần lưu bằng chứng cho danh sách MST lọc ra, cho PAD chạy quét lại và chụp ảnh là tối ưu nhất!

Còn nếu bạn thích dùng python luôn vẫn có cách làm có thể dùng Playwright / Selenium. Bạn nghiên cứu tiếp xem thế nào.
 
Thông thường đối với kế toán hiện nay, ngoài việc tra cứu thông tin thì còn có 1 nhu cầu khác là chụp ảnh màn hình lại, nhằm mục đích lưu lại bằng chứng tại thời điểm tra cứu doanh nghiệp đó vẫn còn hoạt động. Sau này khi đơn vị bên kia không may bị dính vào black list của cơ quan thuế thì công ty còn có bằng chứng để giải trình.
Dựa vào code tác giả em đã dựng 1 file .exe để tra cứu thông tin, mọi thứ chạy mượt mà, duy chỉ có muốn chụp màn hình thì phải thực hiện nhiều request tới thuế hơn, mỗi mã ngoài việc tra cứu, còn thêm cả chục request để tải logo/ảnh/CSS về hiển thị, làm cho lưu lượng tăng gấp nhiều lần. Việc này làm cho thuế block ngắn hạn địa chỉ IP, chỉ tra và chụp khoảng 2-3 mã thì ổn, chứ nhiều quá thì bị block ngay.
Có bác nào có hướng giải quyết không ạ, em mò mò từ qua tới nay mà vẫn đang bó tay.
View attachment 312140
Bác có thể share cho ace trong group không bác
 
Anh vào link sau nha: https://tracuunnt.gdt.gov.vn/tcnnt/mstdn.jsp
Như thường lệ sau khi tra cứu 1 mã số thuế nào đó, kế toán một vài cty sẽ chụp màn hình lại, có ngày giờ máy tính để làm căn cứ xác minh tại thời điểm tra cứu doanh nghiệp đó vẫn còn hoạt động.

Nếu chỉ đơn giản là tra cứu thông tin, code hiện tại sẽ chỉ request để nhận mã capcha, giải và gửi câu trả lời, rồi chờ nhận thông tin phản hồi.
Còn nếu mở trình duyệt lên, thì ngoài request thông tin sẽ còn có các yêu cầu khác như lấy logo, file trang trí CSS/JS, lấy hình nền, nút bấm, icon... số lượng request sẽ nhiều lên và mỗi lần tải 1 mã số thuế là 1 lần request lại từ đầu tất cả, điều này làm cho sever thuế block tạm thời địa chỉ IP, theo em hiểu là vậy.

Bạn cho hỏi, do trang tra cứu không có ngày giờ, như vậy phải chụp toàn bộ màn hình Windows, cả ngày giờ ở góc dưới bên phải? Có hợp lệ không nhỉ, vì ngày giờ Windows thay đổi được.
 
Giờ thấy bà con train model AI này nọ nên mình cũng phải tìm hiểu thêm chút cho đỡ mù AI.
Muốn train nhận diện cái captcha của trang tracuunnt mà ngồi label 1.000 cái file ảnh mới tải về để train thì cũng chua thật (cũng dùng ddddocr nhận dạng xử lý trước rồi). Tôi chỉ dùng code có người ta viết sẳn để train thôi, chứ mà tìm hiểu chi tiết vô nữa thì bó tay.

Screenshot 2026-07-23 at 11.29.50 PM.png


Tôi có 1 bộ Captcha mẫu (1.000 và 10.000 hình) này chia sẻ để các bạn tập tành train cho vui.
Link:
https://www.mediafire.com/file/faw9a59u3lgsgog/CAPTCHA.zip/file
https://www.mediafire.com/file/9mvv4sov84z574d/captcha-2.zip/file
 
Lần chỉnh sửa cuối:
Do mình không có quyền sửa bài viết bài 1 nên mình đăng bài ở đây.

..

Bước 3:
Cài đặt các thư viện cần thiết của python:

Mở cửa sổ Command Prompt (CMD) trên máy tính và dán dòng lệnh sau bấm Enter:

"C:\Users\Ten_User\AppData\Local\Programs\Python\Pythonxxx\python.exe" -m pip install requests

"C:\Users\ Ten_User \AppData\Local\Programs\Python\Pythonxxx\python.exe" -m pip install pillow

"C:\Users\Ten_User\AppData\Local\Programs\Python\Pythonxxx\python.exe" -m pip install pytesseract

"C:\Users\Ten_User\AppData\Local\Programs\Python\Pythonxxx\python.exe" -m pip install beautifulsoup4

"C:\Users\Ten_User\AppData\Local\Programs\Python\Pythonxxx\python.exe" -m pip install "numpy<2.0.0"

"C:\Users\Ten_User\AppData\Local\Programs\Python\Pythonxxx\python.exe" -m pip install pandas
Tất cả các bước này bạn list toàn bộ các thư viện cầng cài thành 1 file requirement.txt rồi cài đặt bằng

python -m pip install -r requirements.txt

Mã:
# Thu vien cho cong cu tra cuu MST ca nhan/doanh nghiep GPE.
# Ho tro Python 3.11 tro len. Cai bang: python -m pip install -r requirements.txt

requests>=2.31,<3
Pillow>=10,<13
pytesseract>=0.3.10,<0.4
beautifulsoup4>=4.12,<5
pandas>=2.2,<3
openpyxl>=3.1,<4

Bạn có tham khảo thêm bên dưới.
 

File đính kèm

Trong lúc chờ tác giả chia sẻ code các bác có thể ngâm cứu code này trên github coi có dùng được món gì không nhé! https://github.com/luckycloudyoursky/tracuunnt1
Code này cũng hay, sử dụng toàn bộ Playwright nên an toàn, ít bị chặn hơn request, không phải giả lập nhiều thứ. Vấn đề tốn thời gian vẫn là OCR, captcha Cục thuế tuy đơn giản nhưng là font vẽ mập ốm khác nhau, thường các ký tự dính liền nhau, nên ddddocr hay Tesseract cũng như nhau, có lúc giải phát một, có lúc thử đi thử lại vài lần mới được.
 
Code này cũng hay, sử dụng toàn bộ Playwright nên an toàn, ít bị chặn hơn request, không phải giả lập nhiều thứ. Vấn đề tốn thời gian vẫn là OCR, captcha Cục thuế tuy đơn giản nhưng là font vẽ mập ốm khác nhau, thường các ký tự dính liền nhau, nên ddddocr hay Tesseract cũng như nhau, có lúc giải phát một, có lúc thử đi thử lại vài lần mới được.
Theo tôi thấy là tessertact và ddddocr giải đúng ngay 1 lần đó chứ ( không phải làm 100%), chẳng qua là trang web cho không cho kết quả ngay thôi. Tôi nhập trực tiếp bằng tay mà còn có khi đến 5 lần mới có kết quả đó thôi.
Bạn vô trang làm thử là biết ngay thôi.
 
Theo tôi thấy là tessertact và ddddocr giải đúng ngay 1 lần đó chứ ( không phải làm 100%), chẳng qua là trang web cho không cho kết quả ngay thôi. Tôi nhập trực tiếp bằng tay mà còn có khi đến 5 lần mới có kết quả đó thôi.
Bạn vô trang làm thử là biết ngay thôi.
Có lẽ vậy, nhiều lúc thử trên web cả 10 lần vẫn không được, reload cũng lúc được lúc không. Chắc trang bị lỗi.
 
Cám ơn tác giả rất nhiều để không cần cài thêm Tesseract-OCR\tesseract.exe mình đã text thử python314; và các thư viện ddddocr; pandas; openpyxl sau đó biên dịch ra file .exe là chạy tốt.
Lần nữa cám ơn tác giả đã đầu tư công, sức vật lộn với một loạt code để chia sẽ anh em nghiên cứu.
bÁC CÓ THỂ ULTRAL CÀI GIÚP EM VỚI Ạ!
 
Theo tôi thấy là tessertact và ddddocr giải đúng ngay 1 lần đó chứ ( không phải làm 100%), chẳng qua là trang web cho không cho kết quả ngay thôi. Tôi nhập trực tiếp bằng tay mà còn có khi đến 5 lần mới có kết quả đó thôi.
Bạn vô trang làm thử là biết ngay thôi.
Trang của Cục thuế sử dụng Load Balancer để phân luồng truy cập, nhưng có vẻ đang bị lỗi. Khi tạo session captcha, sau đó nhận lại kết quả thì có lúc lại gán vào session khác, nên nhập captcha đúng thì vẫn bị lỗi nhập sai captcha. Hậu quả, người dùng web mất thời gian tra cứu, lúc được lúc không, còn ae viết code tra cứu hàng loạt đổ lỗi oan cho OCR như ddddocr, Tessertact, mất thời gian chỉnh sửa.
 
Trang của Cục thuế sử dụng Load Balancer để phân luồng truy cập, nhưng có vẻ đang bị lỗi. Khi tạo session captcha, sau đó nhận lại kết quả thì có lúc lại gán vào session khác, nên nhập captcha đúng thì vẫn bị lỗi nhập sai captcha. Hậu quả, người dùng web mất thời gian tra cứu, lúc được lúc không, còn ae viết code tra cứu hàng loạt đổ lỗi oan cho OCR như ddddocr, Tessertact, mất thời gian chỉnh sửa.
Có kỹ thuật nào khắc phục không bạn?
 
Có kỹ thuật nào khắc phục không bạn?
Mình cũng kiểm tra nhưng chưa tìm ra qui tắc. Cho ddddocr giải mã captcha từ web Cục thuế thì đúng 100%. Nhưng khi ráp vào tra cứu, vẫn bị báo sai kha khá. Tạm thời thì thử nhiều lần vẫn được trả lời thành công. Nếu Cục thuế fix lỗi này thì tốc độ tra cứu sẽ nhanh hơn.
 

Bài viết mới nhất

Back
Top Bottom