把處理天氣預報的PDF 那個檔案重構一下,改成物件的方式,去呼叫,檔案名稱叫lib/pdfWeather.py,這個就專門處理PDF的格式。
檔案結構
<projectName>/
----manage.py
----<projectName>/
--------__init__.py
--------settings.py
----main/
----venv/
----lib/
--------pdfWeather.py
--------font/kaiu.pdf
--------pdfWeather.py
lib/pdfWeather.py
將之前的程式分為兩個部份,
第一個是 call 天氣的API,然後轉換成比較簡潔的格式,再回傳這個資料。
CrawlerWeatherAPI() 局部程式碼,這裡省略了一些重複的部份,請參考前幾天寫的,在getCrawlerData 多傳了locationNameList,會多判斷要回傳的區,如果指定要回傳哪一區,就回傳全部。
class CrawlerWeatherAPI:
def getCrawlerData(self, locationNameList=[]):
authorization = "xxxxx"
url = "https://opendata.cwb.gov.tw/api/v1/rest/datastore/F-D0047-061"
res = requests.get(url, {"Authorization": authorization})
resJson = res.json()
dataDictList = []
locations = resJson["records"]["locations"][0]["location"]
for index, location in enumerate(locations):
locationName = location["locationName"]
# if not in list continue
# 如果有傳就判斷,如果 沒有在這個list就continue
if locationNameList and locationName not in locationNameList:
continue
weatherElements = location["weatherElement"]
temperatureDictList = []
aTemperatureDictList = []
pop6HDictList = []
wxDictList = []
ciDictList = []
for weatherElement in weatherElements:
# 溫度
if weatherElement["elementName"] == "T":
timeDicts = weatherElement["time"]
for timeDict in timeDicts:
temperatureDictList.append({
"dataTime": timeDict["dataTime"],
"value": timeDict["elementValue"][0]["value"],
})
# 體感溫度
if weatherElement["elementName"] == "AT":
...
# 降雨機率 百分比
if weatherElement["elementName"] == "PoP6h":
...
# 天氣現象 Text
if weatherElement["elementName"] == "Wx":
...
# 舒適度指數
if weatherElement["elementName"] == "CI":
...
tempDict = {
"locationName": locationName,
"temperatureDictList": temperatureDictList,
"aTemperatureDictList": aTemperatureDictList,
"pop6HDictList": pop6HDictList,
"wxDictList": wxDictList,
"ciDictList": ciDictList,
}
dataDictList.append(tempDict)
return dataDictList
第二部份,就是處理PDF樣式的程式,一樣也是貼局部,叫 PdfWeather(),這裡因為多加了一層lib/資料夾,執行根位置是在上一層,所以會找不到檔案,就改成絕對位置吧,不過也是用程式抓這個檔案位置加上的,os.path.dirname(__file__)抓目前的檔案位置資料夾
所有用到位置的都要加上這行,用到位置的有,標楷體字體檔案位置,輸出檔案位置。
在__init__() 有傳dataDictList,就是傳抓到的資料,這邊就直接顯示就好,不做任何資料處理,還有傳fileName,可以指定位置儲存。
在export(),就是產生pdf 把資料list 跑迴圈去呼叫之前寫好的表格和圖表。
styles = getSampleStyleSheet()
styleNormalCustom = ParagraphStyle(
'styleNormalCustom',
fontName='kaiu',
parent=styles["Normal"],
alignment=TA_CENTER,
)
...
class PdfWeather:
def __init__(self, dataDictList, fileName=None):
# 抓目前的檔案位置資料夾
filePath = os.path.dirname(__file__)
fontPath = os.path.join(filePath, "font/kaiu.ttf")
pdfmetrics.registerFont(TTFont('kaiu', fontPath))
if fileName:
self._fileName = fileName
else:
self._fileName = os.path.join(filePath, "example.pdf")
self._dataDictList = dataDictList
def export(self):
todayDate = datetime.datetime.today().date()
tomorrow = todayDate + datetime.timedelta(days=1)
tomorrowText = tomorrow.strftime('%Y-%m-%d')
pdfTemplate = SimpleDocTemplate(self._fileName)
story = []
for dataDict in self._dataDictList:
story.append(Paragraph("未來鄉鎮天氣預報", style=styleNormalCustomHeader))
story.append(Spacer(1, 0.15 * inch))
story.append(Paragraph(dataDict["locationName"], style=styleNormalCustomHeader2))
story.append(Spacer(1, 0.15 * inch))
table = self.getPDFTableDistrict(dataDict, tomorrowText)
story.append(table)
story.append(Spacer(1, 0.15 * inch))
story.append(Paragraph("未來鄉鎮溫度折線圖", style=styleNormalCustomHeader2))
chart = self.getPDFChartDistrict(dataDict, tomorrowText)
story.append(chart)
story.append(Spacer(1, 0.2 * inch))
story.append(Paragraph("未來鄉鎮降雨機率折線圖", style=styleNormalCustomHeader2))
chart = self.getPDFChartDistrict2(dataDict, tomorrowText)
story.append(chart)
story.append(PageBreak())
pdfTemplate.build(story)
# 處理溫度、體感溫度圖表
def getPDFChartDistrict(self, dataDict, showDateText):
...
return drawing
# 處理降雨機率的圖表
def getPDFChartDistrict2(self, dataDict, showDateText):
...
return drawing
# 處理表格顯示 所有欄位的表格
def getPDFTableDistrict(self, dataDict, showDateText):
...
return table
會這樣做,是想把權責分清楚,在之後維護上或找bug會比較好找。
當然也可以不用這樣做,這是我寫程式的習慣而已。