索引
實習內容
我去國稅局實習一個禮拜,負責的部門是營所稅申報,做的內容大概是把紙本申報的內容填成線上申報

開始搞事(o)
我觀察到在填表的時候,營利事業基本資料很多都是網路上登記的公開資訊,所以,能不能只用統一編號,就把大部分的基本資料填完呢?
實作
在正式寫程式之前,我要先搞清楚附檔名.001的格式是甚麼
在經過了一段痛苦的trial and error之後
我整理出了基本資料的表格
不是全部,因為真的painful
內容大概是這樣:
統編|001(基本資料)|0001(營利事業單位基本資料建檔)|營利事業名稱(中文)|所得期(始)|所得期(末)|開業日期|營業月數|營業地址|組織種類|負責人姓名|負責人住址|統編|身分證註記|營業種類|稅籍編號|行業標準代號|營利事業電話|傳真號碼|縣市代號縮寫|申報書寄送方式|特殊會計年度核准日期|股票發行狀況|勾勾(N/Y)|||國外營利事業英文名稱|國家縮寫|TIN(稅務識別碼)|V111(資料處理年度)|1(試)/2(決)
統編|001(基本資料)|0002(帳簿處理人員與委任代辦,帳簿處理情形)|委任記帳情形|委任人姓名|身分證/統編|身分證號註記|住址|電話|記帳(始)|記帳(末)|||||||||
統編|001(基本資料)|0004(帳簿處理人員與委任代辦,辦理營利事業所得稅結算申報情形)|委任代辦申報情形||||||||||||||
統編|001(基本資料)|0005(營利事業單位基本資料建檔)|email|營利事業名稱(英文)
#這裡內容好像有誤,下面的python code比較準((
然後用python 寫成一個.001 然後匯出
class generate:
def __init__(self) -> None:
self.Business_Accounting_NO = "" #統編
self.business_name = "" #營利事業名稱(中文) 全
self.income_start = str(1110101) #所得期(始)
self.income_end = str(1111231) #所得期(末)
self.company_setup_date = "" #開業日期
self.active_month = str(12) #營業月數
self.company_address = "" #營業地址 全
self.unit_type = "" #組織種類
self.company_owner_name = "" #負責人姓名 全
self.owner_address_name = self.company_address #負責人住址 全
self.owner_ID = "" #身分證/統編
self.owner_id_pointer = str(0) #身分證註記
self.company_type = "" #營業種類
self.tex_number = "" #稅籍編號
self.standred_company_type = "" #行業標準代號
self.compeny_tele = "" #營利事業電話
self.company_fax = "" #傳真號碼
self.state_type = "" #縣市代號縮寫
self.apply_method = str(1) #申報書寄送方式
self.special_tex_year_date = "" #特殊會計年度核准日期
self.accept_name = ""
self.stock_status = "" #股票發行狀況
self.P1_check_box = str("N") #勾勾(N/Y)
self.non_tw_company_name = "" #國外營利事業英文名稱
self.country_code = str("") #國家縮寫
self.TIN = "" #TIN(稅務識別碼)
self.tex_year = str("V111") #資料處理年度
self.version = str("1") #1(試)/2(決)
self.track_spend_status_P1 = str("0") #委任記帳情形
self.track_spend_status_P2 = str("1") #委任代辦申報情形
self.track_spend_name = "" #委任人姓名
self.track_spend_name_ID = "" #身分證/統編
self.track_spend_name_ID_pointer = str(0) #身分證號註記
self.track_spend_address = "" #住址
self.track_spend_tele = "" #電話
self.track_spend_start = str(1110101) #記帳(始)
self.track_spend_end = str(1111231) #記帳(末)
self.company_email = "" #Email
self.company_non_tw_company_name = self.non_tw_company_name #營利事業名稱(英文)
def new_file(self, result, manual_info):
self.Business_Accounting_NO = result["Business_Accounting_NO"]
self.business_name = result["business_name"]
self.company_setup_date = result["company_setup_date"]
self.company_address = result["company_address"]
self.track_spend_address = result["company_address"]
self.unit_type = result["unit_type"]
self.company_owner_name = result["company_owner_name"]
self.track_spend_name = result["company_owner_name"]
self.owner_ID = result["Owner_ID"]
self.track_spend_name_ID = result["Owner_ID"]
self.tex_number = result["tex_number"]
clipboard(result["tex_number"])
self.compeny_tele = result["compeny_tele"]
self.state_type = result["state_type"]
self.company_email = result["company_email"]
self.unit_type = manual_info["unit_type"]
self.standred_company_type = manual_info["standred_company_type"]
with open(f"{self.Business_Accounting_NO}.001","w",encoding="utf-8") as f:
f.write(f"{self.Business_Accounting_NO}|001|0001|{self.business_name}|{self.income_start}|{self.income_end}|{self.company_setup_date}|{self.active_month}|{self.company_address}|{self.unit_type}|{self.company_owner_name}|{self.owner_address_name}|{self.owner_ID}|{self.owner_id_pointer}|{self.company_type}|{self.tex_number}|{self.standred_company_type}|{self.compeny_tele}|{self.company_fax}|{self.state_type}|{self.apply_method}|{self.special_tex_year_date}|{self.accept_name}|{self.stock_status}|{self.P1_check_box}|||{self.non_tw_company_name}|{self.country_code}|{self.TIN}|{self.tex_year}|{self.version}\n")
f.write(f"{self.Business_Accounting_NO}|001|0002|{self.track_spend_status_P1}|{self.track_spend_name}|{self.track_spend_name_ID}|{self.track_spend_name_ID_pointer}|{self.track_spend_address}|{self.track_spend_tele}|{self.track_spend_start}|{self.track_spend_end}|||||||||\n")
f.write(f"{self.Business_Accounting_NO}|001|0004|{self.track_spend_status_P2}||||||||||||||\n")
f.write(f"{self.Business_Accounting_NO}|001|0005|{self.company_email}|{self.company_non_tw_company_name}")
ok,我現在有一個可以建立匯入檔的程式碼了,現在我需要去網路上找這家公司的登記資訊.
我選了兩個平台:
第一:經濟部商工行政資料開放平臺 (連結)
第二:網路報稅-密碼管理 (連結)
第二個平台其實google 有index 到,但是他上面寫“稽徵機關專用”,所以連結就不放了
再來就是我不懂為什麼密碼管理可以用統編查到公司資料,just don’t make sense
anyway 平台二有圖形驗證碼要驗證,而驗證碼內容是cookie來代表
所以我要先請求到主登入畫面
def main():
r = requests.get(url="https://example.com",timeout=5)
然後使用 r.cookies 來傳給其他 function
像這樣:
def solve_captcha(cookie):
headers = {}
while True:
r = requests.get(url=f"https://example.com/validateCode?{math_random()}=", cookies=cookie, headers=headers)
captcha = sdk.predict(image_bytes=r.content)
print(f"Trying captcha: {captcha}")
if len(captcha) >= 6:
return captcha, r.cookies
def do_login(cookie):
login_headers = {}
while True:
captcha, new_cookie = solve_captcha(cookie)
login_data= {}
login = requests.post(url= "https://example.com", data=login_data, cookies=new_cookie, headers=login_headers)
#print(login.text)
soup = BeautifulSoup(login.content, "html.parser")
title = soup.title.string if soup.title else "No title found"
print(title)
if title == "報稅密碼管理":
return new_cookie
def main():
r = requests.get(url="https://svc.tax.nat.gov.tw/svc/agy_login.jsp",timeout=5)
cookie = do_login(r.cookies)
這樣可以自動過驗證碼
而使用的package是 muggle-ocr
以200MB 來說這個準確率蠻高的
只是6碼對他來說還是太吃力((
不過
沒有什麼是while loop不能解決的∠( ᐛ 」∠)_
ChatGPT prompt
你可以用這個prompt 來re-format HTTP header
i will enter a set of browser request header
you will need to reformat to the python dictionary in order to use it in python requests package. directly to answer, you dont need to say/explain what did you do or how to use it, just straight to the point (header = {}, can use markdown)
just for a finishing touch, remove `content-length` and `cookie` both key and value if the requested data is included, you still don't need to explain what did you do or remove, just straight to the point.(header = {}, can use markdown)
next message will send the header.
他會把你丟進去的header 整理成python 的dictionary
header = {“key”:”value”}
在實作的時候還蠻實用( ´▽` )ノ
爬蟲
因為要從平台二把查詢內容擷取下來,我寫了一個簡易爬蟲來做到這個結果
def get_ben_info(cookie, id):
ban_headers = {}
while True:
ban_data = {"ban": f"{id}"}
result = requests.post(
url="https://example.com/legit_url_path?DO=SELECT",
data=ban_data,
cookies=cookie,
headers=ban_headers
)
soup = BeautifulSoup(result.text, "html.parser")
info_div_element = soup.find('div', class_='alert alert-info') #find class
if not info_div_element:
continue
info_elements = info_div_element.find_all('font', color='#FF0000', size='2') #find another class
info = [element.text.strip() for element in info_elements]
success_div_element = soup.find('div', class_='alert alert-success')
success_info_elements = success_div_element.find_all('font', color='#FF0000', size='2')
info.extend([element.text.strip() for element in success_info_elements[2:5]])
因為是存成 List,但我想要用Dictionary,所以
result = {
"update_date": info[0],
"Business_Accounting_NO": info[1],
"Owner_ID":info[2],
"business_name": half2full(info[3]),
"unit_type": info[4],
"state_type": info[5],
"tex_number":info[6],
"company_owner_name": half2full(info[7]),
"compeny_tele":info[8],
"company_email":info[9],
"company_address": half2full(info[10]),
"company_setup_date":info[11]
}
ㄏ我是天才
全形/半形
在申報軟體裡面,商業名稱、地址、負責人姓名的是全形,不是半形
def half2full(text):
fullwidth_text = ''
for char in text:
code = ord(char)
if 0x0020 <= code <= 0x7e:
code += 0xfee0
elif code == 0x0020:
code = 0x3000
fullwidth_text += chr(code)
return fullwidth_text
解決( ´▽`)
剪貼簿
申報軟體在匯入資料需要填入稅籍編號來匯入,一樣迷之操作,除非.001有加密
def clipboard(content):
# Open the clipboard
win32clipboard.OpenClipboard()
# Clear the existing clipboard content
win32clipboard.EmptyClipboard()
# Set the new content
win32clipboard.SetClipboardText(content)
# Close the clipboard
win32clipboard.CloseClipboard()
自動填入
建檔之間要先新增統編和公司名
翻了一下檔案存在 C:\ETAX\PIAV\Pia.lni 裡
格式為
[LASTLOGIN]
LastLoginBan={id}
LastLoginBanName={business_name}
def main():
print("killing PIA...")
os.system("taskkill /IM PIA.exe /F")
os.system("del C:\\ETAX\\PIAV\\Pia.Ini")
path = r'C:\ETAX\PIAV\Pia.Ini'
print("making new Pia.ini")
os.makedirs(os.path.dirname(path), exist_ok=True)
with open(path,'w',encoding="utf-8") as f:
f.write(f"[LASTLOGIN]\nLastLoginBan={id}\nLastLoginBanName={business_name}")
f.close()
這是我有點邏輯炸掉的地方,如果我在有.001的情況下,為什麼直接匯入就好,要先填統編和公司名在匯入?
心得
這個工具沒有省太多時間´д` ;但方便的點是他節省了很多繁瑣的過程,讓我只需要把後面的數字填完
然後被審核系統轟爛(翻桌
不說了,來去準備面試的東西