2021年6月22日 星期二
[程式碼] 在Windows使用Python/C#監測檔案是否被修改
2021年4月6日 星期二
[程式碼] 使用Python 爬取內政部戶政司提供之全國門牌資料 (PTT CodeJob案例)
import requests
url = "https://www.ris.gov.tw/info-doorplate/app/doorplate/dateQuery"
data = {
"searchType": "date",
"cityCode": "63000000",
"tkt": "-1",
"areaCode": "63000010",
"village": "",
"neighbor": "",
"sDate": "001-01-01",
"eDate": "110-03-25",
"_includeNoDate": "on",
"registerKind": "0",
"floor": "",
"lane": "",
"alley": "",
"number": "",
"number1": "",
"ext": "",
"_search": "false",
"nd": "1616602191259",
"rows": "20",
"page": "1",
"sidx": "",
"sord": "asc",
"token": ""
}
r = requests.post(url, data=data)
r.encoding='utf-8'
f = open(r'dump.txt', 'w', encoding="utf-8")
f.write(r.text)
f.close()
[真實案例] 使用Python 爬取內政部戶政司提供之全國門牌資料 (PTT CodeJob案例)
2021年3月30日 星期二
使用C#與Python實作遊戲修改大師
右邊文本框在視窗初始化時,顯示全域變數的位址
搜尋目標數值前,我們先使用GetSystemInfor取得應用程式的記憶體上下限
再利用VirtualQueryEx確定記憶體區塊屬性為可讀可寫
最後我們使用WriteProcessMemoroy去修改測試程式的記憶體數值
[程式碼] Python修改程式記憶體
import io, sys
try:
sys.stdout=io.TextIOWrapper(sys.stdout.buffer,encoding='utf8')
except:
pass
import win32api, win32gui, win32con, win32process, win32security
from ctypes import *
from ctypes import wintypes
liAddr = []
# https://www.programcreek.com/python/example/114361/win32security.AdjustTokenPrivileges
def AcquirePrivilege(privilege):
process = win32process.GetCurrentProcess()
token = win32security.OpenProcessToken(
process,
win32security.TOKEN_ADJUST_PRIVILEGES | win32security.TOKEN_QUERY)
priv_luid = win32security.LookupPrivilegeValue(None, privilege)
privilege_enable = [(priv_luid, win32security.SE_PRIVILEGE_ENABLED)]
#privilege_disable = [(priv_luid, win32security.SE_PRIVILEGE_REMOVED)]
win32security.AdjustTokenPrivileges(token, False, privilege_enable)
#https://yiyibooks.cn/__trs__/meikunyuan6/pywin32/pywin32/PyWin32/win32api__GetSystemInfo_meth.html
'''
wProcessorArchitecture
dwPageSize
lpMinimumApplicationAddress
lpMaximumApplicationAddress
dwActiveProcessorMask
dwNumberOfProcessors
dwProcessorType
dwAllocationGranularity
'''
# http://www.rohitab.com/discuss/topic/39525-process-memory-scannerpy/
# https://forums.codeguru.com/showthread.php?560337-Windows-Python-Memory-Scanner
# https://mpxd.net/code/jan/mem_edit/commit/5c75da31d5a7ec1e43f9ab542c1f8b4eea01f44a?lang=ja-JP
class MEMORY_BASIC_INFORMATION32(Structure):
_fields_ = [
('BaseAddress', wintypes.DWORD),
('AllocationBase', wintypes.DWORD),
('AllocationProtect', wintypes.DWORD),
('RegionSize', wintypes.DWORD),
('State', wintypes.DWORD),
('Protect', wintypes.DWORD),
('Type', wintypes.DWORD),
]
class MEMORY_BASIC_INFORMATION64(Structure):
_fields_ = [
('BaseAddress', c_ulonglong),
('AllocationBase', c_ulonglong),
('AllocationProtect', wintypes.DWORD),
('RegionSize', c_ulonglong),
('State', wintypes.DWORD),
('Protect', wintypes.DWORD),
('Type', wintypes.DWORD),
]
def ScanMemStep0(hProcess, nSize, nValue): # 從頭開始尋找記憶體並記錄匹配位址
li = win32api.GetSystemInfo()
BaseAddr = li[2]
MaxAddr = li[3]
global liAddr
liAddr = []
windll.kernel32.VirtualQueryEx.argtypes = [wintypes.HANDLE,
wintypes.LPCVOID,
c_void_p,
c_size_t]
while BaseAddr < MaxAddr:
PTR_SIZE = sizeof(c_void_p)
if PTR_SIZE == 8: # 64-bit python
MEMORY_BASIC_INFORMATION = MEMORY_BASIC_INFORMATION64
elif PTR_SIZE == 4: # 32-bit python
MEMORY_BASIC_INFORMATION = MEMORY_BASIC_INFORMATION32
MBI = MEMORY_BASIC_INFORMATION()
MBI_pointer = byref (MBI)
size = sizeof (MBI)
windll.kernel32.VirtualQueryEx(
hProcess,
BaseAddr,
MBI_pointer,
size)
if MBI.Protect == win32con.PAGE_READWRITE and \
MBI.State == win32con.MEM_COMMIT:
for i in range(0, MBI.RegionSize, nSize):
data = win32process.ReadProcessMemory(hProcess, MBI.BaseAddress+i, nSize)
if int.from_bytes(data, byteorder='little') == nValue:
liAddr.append(MBI.BaseAddress+i)
BaseAddr += MBI.RegionSize
def ScanMemStep1(hProcess, nSize, nValue): # 接續尋找變更資料後的記憶體
global liAddr
for i in range(len(liAddr)-1, -1, -1):
data = win32process.ReadProcessMemory(hProcess, liAddr[i], nSize)
if int.from_bytes(data, byteorder='little', signed=True) != nValue:
liAddr.pop(i)
def WriteMem(hProcess, nSize, nValue): # 修改記憶體內容
global liAddr
if len(liAddr) != 1:
return
# 使用此方式異常
# buffer = nValue.to_bytes(nSize, byteorder="little", signed=True)
# win32process.WriteProcessMemory(hProcess, liAddr[0], buffer)
windll.kernel32.WriteProcessMemory.argtypes = [c_void_p, c_void_p, c_void_p, c_int, c_void_p]
lpNumberOfBytesWritten = c_size_t(0)
windll.kernel32.WriteProcessMemory(hProcess,
c_char_p(liAddr[0]), # lpBaseAddress
addressof(c_longlong(nValue)), # lpBuffer
nSize,
byref(lpNumberOfBytesWritten))
if __name__ == "__main__":
AcquirePrivilege("SeTimeZonePrivilege")
hWnd = win32gui.FindWindow(None, "維京碼農")
if hWnd != 0:
tid, pid = win32process.GetWindowThreadProcessId(hWnd)
'''
hProcess = win32api.OpenProcess(win32con.PROCESS_QUERY_INFORMATION |
win32con.PROCESS_VM_READ |
win32con.PROCESS_VM_WRITE,
False,
pid)
'''
hProcess = windll.kernel32.OpenProcess(win32con.PROCESS_QUERY_INFORMATION |
win32con.PROCESS_VM_READ |
win32con.PROCESS_VM_WRITE,
False,
pid)
while True:
str = input("Input Scan Step、Size And Value: ")
liStr = str.split(" ")
if liStr[0] == "0":
ScanMemStep0(hProcess, int(liStr[1]), int(liStr[2]))
print("Count Of liAddr = %d\n" % len(liAddr))
elif liStr[0] == "1":
ScanMemStep1(hProcess, int(liStr[1]), int(liStr[2]))
print("Count Of liAddr = %d\n" % len(liAddr))
if len(liAddr) == 1:
print("Addr Of Value = %x\n" % liAddr[0])
elif liStr[0] == "w":
WriteMem(hProcess, int(liStr[1]), int(liStr[2]))
elif liStr[0] == "q":
print("Bye Bye")
else:
print("App Not Found")
input("Press Any Key...")
2021年3月28日 星期日
[程式碼] Python+Firefox+網頁XPath取得GoodInfo股票資訊
2021年2月27日 星期六
Python+Firefox+網頁XPath取得GoodInfo股票資訊
今天我們要講解的是,如何使用Firefox+Python+網頁XPath來抓取GoodInfo股票資訊
Python使用的套件為requests、re與lxml
requests可以幫助取得網頁內容
re能夠快速取得或移除字串內容
lxml則能夠從網頁中有效的提取資料
今天要抓取的標的是大立光,股票代號3008
首先抓取公司名稱與產業別
這邊使用requests.get取得了網頁內容 ,並填入標頭資料,模擬瀏覽器的行為
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko'
}
UrlCompanyInfo = 'https://goodinfo.tw/StockInfo/StockDetail.asp?STOCK_ID='
strID='3008'
resInfo = requests.get(UrlCompanyInfo+strID, headers=headers)
宣告其編碼為UTF-8
resInfo.encoding='utf-8'
並使用etree.HTML解析
htmlInfo = etree.HTML(resInfo.text)
接著使用xpath取出公司名稱與產業別節點內容,因為lxml不認得tbody,所以要使用re將tbody給取代成空白
XpathCompanyName = '/html/body/table[2]/tbody/tr/td[3]/table/tbody/tr[2]/td[3]/table[2]/tbody/tr[1]/td[2]'
CompanyName = htmlInfo.xpath(re.sub(r'/tbody([[]\\d[]])?', '', XpathCompanyName) + '/text()')[0]
XpathCompanyIndustry = '/html/body/table[2]/tbody/tr/td[3]/table/tbody/tr[2]/td[3]/table[2]/tbody/tr[2]/td[2]'
CompanyIndustry = htmlInfo.xpath(re.sub(r'/tbody([[]\\d[]])?', '', XpathCompanyIndustry) + '/text()')[0]
最後將資料印出
print(CompanyName)
print(CompanyIndustry)
那網頁的節點該如何去尋找呢?
首先連到goodinfo中的StockDetail頁面
接著往下拉到公司基本資料表格中的名稱,點選右鍵選擇檢測元素,
Firefox檢測器會跳到該節點位置,選擇複製XPath,即可抓取公司名稱節點
同樣對產業別內容點選右鍵,選擇檢測元素
檢測器會跳到該節點位置,選擇複製XPath,即可抓取產業別內容節點
接著來抓取股利政策,來到StockDividendPolicy頁面,對表格內容點選檢測元素
會發現到有些資料佔用的不只一列或一欄
因此,需要把佔用的欄跟列補上資料,這樣才不會抓出來的標頭是空字串
再來設定要抓取的資料
最後來抓取獲利指標,來到StockBzPerformance頁面,對表格內容點選檢測元素
跟股利政策頁面一樣,會有些資料佔用的不只一列或一欄
一樣把佔用的欄跟列補上資料
再來設定要抓取的資料
教學與操作影片
6月 22, 2021


Posted in: 






























