2017年6月20日 星期二

Python邊學邊記錄-pyautogui-影片圖片識別

Python pyautogui

稍早提了一些pyautogui的基礎功能,這個部份想說應該另外拉出來記錄!
pyautogui可以處理簡單的圖片識別,比方說,我想讓程式自動幫我找尋『儲存』的座標,然後再透過click去執行,這時候我們的執行流程如下說明。
step-1
把圖片剪下來
step-2
pyautogui.locateOnScreen('test.png')  #  檔案名稱依自己設置處理
step-3
這時候就可以取得回傳值了,舉例來說,(1487, 133, 65, 26)  #  x, y, 寬, 高
Python autogui
step-4
pyautogui.center((1487, 133, 65, 26))  #  取得該圖像的中間值(1519,146)
pyautogui.click((1519, 146))  #  點擊

要先說的就是,只要圖片有一點點點的不對勁就比對不到!!
不過拿來做遊戲的腳本應該很好作業才對,比方說...自動掛機練功這樣,哈哈!

Python邊學邊記錄-pyautogui

Python pyautogui

pyautogui是一個可以自動化操作滑鼠與鍵盤的lib,但是也要注意失控問題!

import pyautogui
pyautogui.PAUSE = 1 # 代表每次呼叫執行動作之後都會停一秒
pyautogui.FAILSAFE = True # 啟用失效安全防護
當啟用了失效安全防護的話,只要將滑鼠移到左上角滑啊滑,就會觸發了!

使用之前,簡單說明一下,左上角的座標是(0,0),右下角是(1919,1079),沒有負值,最主要還是看個人所設置的螢幕解析度為何。
不確定的情況下可以透過指令來取得目前的解析度
pyautogui.size()
width, height = pyautogui.size()
這樣子就可以直接把x、y的值給了width與height了!

接著,我們就試著讓鼠標動一動了,主要是使用pyautogui.moveTo(1, 2, duration=3)
1-x,2-y,3-表是移到那地方需要的秒數,如果不設定的話就預設為0,就是立馬就會到達的意思!

如下圖所見,會看到執行之後就開始跑圈圈,然後我趁著執行間的空檔(pyautogui.PAUSE = 1)把滑鼠弄到左上角去滑啊滑,就會觸發失效安全防護的機刷!
Python pyautogui

如果想取得目前的滑標位置,也可以透用position來取得!
pyautogui.position()

如果想要透過迴圈來一直取得x,y的話,也可以達到。
print('Press Ctrl-C to exit.')
try:
    x, y  = pyautogui.position()
    positionStr = 'X: ' + str(x).rjust(4) + ' Y: ' + str(y).rjust(4)  #  rjust會讓字串靠右,並且佔同樣寬
    print(positionStr, end='')
    print('\b' * len(positionStr), end='', flush=True)
    #  \b用來刪除螢幕上目前行末的字元,故乘上字串長度,可將目前的文字擦掉
except KeyboardInterrupt:
    print('\nDone.')

在已經知道怎麼取得座標之後,再來就是怎麼讓程式幫我們控制點一下!
利用的是click這個method
pyautogui.click(1, 2, button=3)
#  1-x軸,2-y軸,3-左(left)右(right)鍵
pyautogui(100, 100, buggon="left")
#  click是按一下,按了放開的按一下。
#  也有pyautogui.doubleClick()、pyautogui.rightClick(),pyautogui.middleClick()…可使用。

拖拉也可以達成
#  引數的部份一樣是x, y, duration=間隔時間
pyautogui.dragTo()
pyautogui.dragRel()

pyautogui也可以取得螢幕截圖
im = pyautogui.screenshot()
im.getpixel((50, 100))  #  取得該座標的rgb
#  假如取得了(255, 200, 250)
pyautogui.pixelMatchesColor(50, 100, (255, 200, 250))
#  這時候會還傳true,該method就是拿來比對該座標的rgb是否相同。



藤原栗子週末碎念-0620

一直以為自己還有兩週可以爽,結果沒有想到,0626就是下週一了....
還好有先去做體檢了,不然我看這個工作應該會飛掉!

昨天趁著岳母帶的一個小孩沒有來,我帶喵喵小姐一起去看了電影,然後好好的逛個大創、吃個午飯,這大概是有泡泡先生以來最悠閒的其中一個日子了!

上禮拜去看了兩間房,一間透天,二十四坪蓋了兩層,然後壁癌嚴重,估計買了還要花快一百萬整理裝潢...開價598,沒有停車位...房仲說,這邊好停車,實在有夠喇叭,另一間是大樓,8樓,40坪,含車位698...還蠻心動的,不過還是想要看能不能談到648之類的就是了,哈!

新工作有SAP、LOTUS、PERL、REPORTING SERVICE要學,要盡快進入狀況了,希望自己三個月內可以進入狀況。

2017年6月16日 星期五

Python邊學邊記錄-csv

Python CSV

csv.reader

python中已有處理csv的lib了,所以使用的時候直接import即可!
import csv
csvFile = open('demo.csv')
csvReader = csv.reader(csvFile)
csvData = list(csvReader)
這樣就可以把資料讀進csvData了
python csv

如果擔心csv檔案過大一次讀入會吃太多記憶體的話,那也可以透過for來處理!
for row in csvReader:
    print('Row:' + str(csvReader.line_num) + ' ' + str(row))
以type去查row的話,它的型態的是list,所以要轉成str來列印!
另外,以迴圈執行完之後,基本上指標已經跑到最後了,所以如果還要再來一次的話,就需要再執行一次csvReader=csv.reader(csvFile)

csv.writer

import csv
wFile = open('demo.csv', 'w', newline='')
wWriter = csv.writer(wFile)
wWriter.writerow(['1','2','3'])
wFile.close()  #  有開門就記得要關門!

這樣子,就會寫入檔案了,不過要注意的是操作的模式,'w'的話是會將檔案重頭開始,這部份當然要看是寫入後面還是怎麼樣子的,依情況來處理!

如果在寫入csv的時候想要改變定位點,不想要用『,』以及想要兩倍行距的話,在writer的時候就要指定了。
wWriter = csv.writer(wFile, delimiter='\t', lineterminator='\n\n')
#  delimiter代表定位點,lineterminator可調整行距







2017年6月15日 星期四

Python 邊學邊記錄-smtplib-mail

Python smtplib

要透過python發mail的話,可以直接使用內函的lib來處理。
import smtplib

以GMAIL為例來看:
smtpObj = smtplib.SMTP('smtp.gmail.com', 587)
smtpObj = smtplib.SMTP_SSL('smtp.gmail.com', 465)

這時候可以透過
smtpObj.ehlo()
來確認是否有回應
smtplib

如果是透過587PORT來接的話,就可以啟用TLS加密,SSL的話,就不用特別使用了!
smtpObj.starttls()

接著就可以登入GMAIL
smtpObj.login('your gamil count', 'your password')

不過測試登入的時候會有錯誤,這還需要到gmail做設定,你會收到一個登入阻擋的通知。
總之…測試一下,無傷大雅!
smtplib
(當然也可以設定應用程式密碼,可參考這文章)
然後重新login之後就會取得成功的訊息了(235, b'2.7.0 Accepted')
接著就可以送信了!
smtpObj.sendmail('your mail address', 'recipient mail address', 'Subject:your title\nYour message')
這邊sendmail分成了三段
your mail address:就是你寄信的mail
recipient mail address:就是收件者的mail
第三個部份分兩段,Subject:一直到\n是主旨,後面才是內容,成功的話,就會回一個{}
然後就可以看一下自己有沒有收到測試信了!

最後,有借有還,開了門就記得要關門!
gmail.quit()

2017年6月14日 星期三

Google Analytics學習筆記-目標設定

Google Analytics 目標設定

網頁目標


  • 造訪的客戶是否有瀏灠某特定目標
  • 追縱特定動作之後的完成頁面,如電子商務網站在完成交易之時帶入感謝頁面,即達成目標

設定方式


  • 管理員\資料檢視\目標
  • Google Analytics
  • GOOGLE ANALYTICS
  • GOOGLE ANALYTICS
  • GOOGLE ANALYTICS

關於程序

  • 在設定網頁目標的時候會發現有一個程序,這部份只有在這邊可以設定,針對事件型與停留型的部份是不行設置的。
  • 最多可以設置20個步驟
  • 主要是設置希望客戶在達成目標的時候所經過的步驟。

其它目標


  • 其它的事件、停留時間以及瀏灠網頁次數也可以直接透過自訂來做設置
  • 基本上預設的範本目標只有幫你打上名字而以,內容的部份還是要自己去設置
  • GOOGLE ANALYTICS,

2017年6月13日 星期二

Python邊學邊記錄-Crawler網路爬蟲-實戰-虎航2_selenium

利用selenium來處理的話,就不需要再去看data帶了什麼資料了!
selenium本身會直接操作browser,所以頁面上的欄位也要直接的給值,而不是去透過data給值了!

首先,先設定好webdriver!
chrome_path = 'D:\pyCrawler\selenium_driver_chrome\chromedriver.exe'driver = webdriver.Chrome(chrome_path)
driver.maximize_window()
driver.set_page_load_timeout(60)
driver.get(TigerUrl)

然後,就要開始找畫面上的欄位定位了!

來回:應該是不用去調整才對!
起發:ControlGroupSearchView_AvailabilitySearchInputSearchVieworiginStation1
抵達:ControlGroupSearchView_AvailabilitySearchInputSearchViewdestinationStation1
去程日:ControlGroupSearchView_AvailabilitySearchInputSearchView_DropDownListMarketDay1
去程年月:ControlGroupSearchView_AvailabilitySearchInputSearchView_DropDownListMarketMonth1
回程日:ControlGroupSearchView_AvailabilitySearchInputSearchView_DropDownListMarketDay2
回程年月:ControlGroupSearchView_AvailabilitySearchInputSearchView_DropDownListMarketMonth2
成人:ControlGroupSearchView$AvailabilitySearchInputSearchView$DropDownListPassengerType_ADT
兒童:ControlGroupSearchView_AvailabilitySearchInputSearchView_DropDownListPassengerType_CHD
嬰兒:ControlGroupSearchView_AvailabilitySearchInputSearchView_DropDownListPassengerType_INFANT
獲取航班:ControlGroupSearchView_ButtonSubmit

element = WebDriverWait(driver, 10, 0.5).until(EC.presence_of_element_located((By.ID,
 'ControlGroupSearchView_ButtonSubmit')))
#  下拉選單需要拆段作業,先定位點擊,然後再巡覽選項#  出發機場el = Select(driver.find_element_by_id(
'ControlGroupSearchView_AvailabilitySearchInputSearchVieworiginStation1'))
el.select_by_value('TPE')
#  抵達機場el = Select(driver.find_element_by_id(
'ControlGroupSearchView_AvailabilitySearchInputSearchViewdestinationStation1'))
el.select_by_value('DMK')
#  去程日el = Select(driver.find_element_by_id(
'ControlGroupSearchView_AvailabilitySearchInputSearchView_DropDownListMarketDay1'))
el.select_by_value('21')
#  去程年月el = Select(driver.find_element_by_id(
'ControlGroupSearchView_AvailabilitySearchInputSearchView_DropDownListMarketMonth1'))
el.select_by_value('2017-06')
#  回程日el = Select(driver.find_element_by_id(
'ControlGroupSearchView_AvailabilitySearchInputSearchView_DropDownListMarketDay2'))
el.select_by_value('30')
#  回程年月el = Select(driver.find_element_by_id(
'ControlGroupSearchView_AvailabilitySearchInputSearchView_DropDownListMarketMonth2'))
el.select_by_value('2017-06')
#  成人數el = Select(driver.find_element_by_id(
'ControlGroupSearchView_AvailabilitySearchInputSearchView_DropDownListPassengerType_ADT'))
el.select_by_value('3')
#  兒童數el = Select(driver.find_element_by_id(
'ControlGroupSearchView_AvailabilitySearchInputSearchView_DropDownListPassengerType_CHD'))
el.select_by_value('0')
#  嬰兒數el = Select(driver.find_element_by_id(
'ControlGroupSearchView_AvailabilitySearchInputSearchView_DropDownListPassengerType_INFANT'))
el.select_by_value('0')
#  按下獲取航班driver.find_element_by_id(
'ControlGroupSearchView_ButtonSubmit').click()
#  透過等待的設定來待網頁,看到需求的元件就往下執行了!WebDriverWait(driver, 10, 0.5).until(EC.presence_of_element_located((By.ID, 'flightSpinner')))

條件的部份後續可以再優化,透過文字檔來處理!
不過基本上這樣子已經可以取得資料了!
# 透過page_source回傳網頁文件給BeautifulSoup處理
soup = BeautifulSoup(driver.page_source, 'html5lib')
tbs = soup.select('.select-flight')

start_lightPrice = soup.select('#tableMarket1 > tr > td')[1].select('label > span')
print('sl:', start_lightPrice)
start_comboPrice = soup.select('#tableMarket1 > tr > td')[2].select('label > span')
print('sc:', start_comboPrice)
end_lightPrice = soup.select('#tableMarket2 > tr > td')[1].select('label > span')
print('el:', end_lightPrice)
end_comboPrice = soup.select('#tableMarket2 > tr > td')[2].select('label > span')
print('ec:', end_comboPrice)

BeautifulSoup也有CSS選擇器,不過在td的部份,一直想透過td.light price來做定位一直無法成功,如果有路過的前輩知道也請指導!

再來處理一下,就可以弄成給預算還有旅遊區間,然後讓程式自動去爬,一但有了就自動發出mail來通知你有便宜的機票了!

不過現在一堆機票搜尋都寫那麼好了....=..=





2017年6月12日 星期一

Python邊學邊記錄-selenium_webdriver

Python Selenium

今天透過BeautifulSoup去虎航的網頁過多次,加上技巧不好,大概是被發現我在爬了吧= =
回頭來透過selenium的webdriver處理也是另一個方式!

透過webdriver如果想開立chrome的話,需要去下載chrome的webdriver!
依著自己的crhome版本來下載-連結!
不放心的話,可以直接google一下,就可以馬上找的到相關資料的!

下載之後,個人的習慣是跟專案放在一起。
chrome_path = 'D:\pyCrawler\selenium_driver_chrome\chromedriver.exe'
driver = webdriver.Chrome(chrome_path)
driver.maximize_window()
driver.set_page_load_timeout(60)
driver.get(TigerUrl)

執行之後,就可以直接開立網頁了!
透過selenium來執行的話,程式會直接的開立網頁,因為這是直接像人在操作一樣了,過於複雜的動態網頁,用這個來處理的話還蠻方便的!
當然還是可以調整成背景作業,不過那是後續優化的事了!

操作記錄

Selenium可以做的事很多,可以find_element_by_id、by_tag、by_class...也可以等待網頁上某個元件一定出現之後才向下繼續執行!

Select Option Dropdownlist

要給下拉選項值的話需要兩段作業,先定位再給值!
作法有兩種:
一、
from selenium.webdriver.support.ui import Select
el = Select(driver.find_element_by_id('id'))
el.select_by_value('option')
二、
driver.find_element_by_id('id').click()
for option in driver.find_element_by_id('id').click():
    if option.text == '':
        option.click()




Python邊學邊記錄-Crawler網路爬蟲-實戰-虎航

Python Crawler

在爬虎航的航班資訊的時候,好像不是這麼標準SOP就可以取得網頁資料了!

透過開發者工具可以發現,這個SelectFlights.aspx是有來源網址的,這代表是在一個地方先搜尋之後再到這來。
Python Crawler

再看一下Search.aspx的部份

Python Crawler

Python Crawler

另外也可以看一下Search.aspx的response會發現是空的!
這代表在這邊是沒有回傳資料的,而SelectFlights.aspx的response是有的!
Python Crawler

Python Crawler

所以,程式的部份就需要改透過request.session來處理!
resp = requests.session()

resp1 = resp.post('https://booking.tigerairtw.com/Search.aspx', data=form_data)
resp2 = resp.get('https://booking.tigerairtw.com/SelectFlights.aspx')

soup = BeautifulSoup(resp2, 'html5lib')

這樣子,就可以取得航班資訊了!
測試的時候更新太多次,被ban了...技術不好就是一下子會被發現是爬蟲…改用selenium了!

2017年6月11日 星期日

藤原栗子週末碎念-0611

呼,天氣真的開始熱了,去了幾趟菜園都快暈了,只能不斷的提醒阿霸、阿目要多喝水了!

上週五去了兩間廠面試,一間是LED廠,一間是封測廠,早上的LED廠面試感覺很不錯,跟主管聊了一下也被點破了自己的盲點,雖是短談也有所收獲,真心的希望可以進入。

至於那封測廠,真的感覺,不去也罷...面試的時候一堆人坐著空等不到相關人員來面試..來了一個面試我的也只要我自我介紹,然後就問我有沒有問題???
你媽的,你都沒有介紹工作給我了,我怎麼知道我還有什麼問題....
當然我就直接跟人事說我要離開了,真的浪費時間!

不過,工作內容比起傳產,似乎有一種沒挑戰性的感覺...都只負責其中一個小模組,我能習慣嗎?

最近被前同事告知了天眼通有八卦,我也忍不住的具名的回應,我想我的光明正大比之於那些躲在螢幕後面說些假消息的人,應該是更有說服力吧?哈哈...

2017年6月8日 星期四

Python邊學邊記錄-wordCloud無法安裝

今天在測wordcloud的時候發現無法安裝,查到github上去,有人回應了一個方法,記錄一下!

error: [WinError 3] 系統找不到指定的路徑。: 'C:\\Program Files (x86)\\Microsoft Visual Studio 14.0\\VC\\PlatformSDK\\lib'



  • Download the .whl file compatible with your Python version and your windows distribution (32bit or 64bit) from here
  • cd to the file path
  • Run this command python -m pip install <filename>

Python邊學邊記錄-套件介紹-collections_Counter

Python collections_Counter

基本上,collections包函很多,不過只先說明有用過的,未來有用到其它功能的時候再回頭補充了!

form collections import Counter

這計數器省了我們不少寫迴圈的麻煩了!

舉例來說,我們有一個list
a = ['a','b','c','d','e','c','a','a']
b = Counter(a)
print(b)
print(b.most_common(1))
collections Counter

很方便吧!

Python邊學邊記錄-jieba結巴與文字雲

Python Jieba WordCloud

jieba是一個可以用來處理文章斷詞分析的,這很有趣,也可以用來看什麼人的習慣用詞!
另外,jieba本身的預設是簡體的詞庫,如果要繁中的話還要再另外設置。
jieba的繁中字典檔在github上可以下載,不信任連結的話可以直接google jieba,就可以找到github的連結了。

首先,會用到的lib
import json
import jieba
from collections import Counter
from wordcloud import WordCloud
import matplotlib.pyplot as plt

jieba.set_dictionart('dict.txt.big')  #  設置繁中字典檔,跟專案放一起就可以指到了

if __name__ == '__main__':
  justDoit()

def justDoit():
    with open('abc.json', 'r', encoding='utf-8') as f:
        data = json.load(f)  #  案例假裝是從json檔取資料

    dicts = list()
    for d in data.values():
        dicts += [s for s in jieba.cut(d) if s.split() and len(s) > 1]
                                          #  當斷詞之後的文字非空格而且長度大於1
    countD = Counter(dicts)  #Counter是上面import的一個lib,很好用,會回傳list內的出現次數
    print(countD)  #  就可以列印出各詞出現的次數了

    #  接著是文字雲,如果是處理中文字,就要附上字型檔,與專案置於同一資料夾即可
    wCloud = WordCloud(font_path='中文字型檔').generate(' '.join(dicts))
    plt.imshow(wCloud)
    plt.axis('off')
    plt.show()

如果詞庫不足的部份也可以自訂延伸出去!

jieba本身的分詞模式包含了預設切分、全切分、搜尋引擎切分…

jieba.cut("來源字串", cut_all=False)  #  預設切分
jieba.cut("來源字串", cut_all=True)  #  全切分
jieba.cut_for_search("來源字串")  #  搜尋引擎切分

我以字串『藤原栗子準備在2017年6月26日去新公司報到了』下去測試。
得到的結果如下圖:
python jieba

Python邊學邊記錄-SQLlite

Python SQLlite

SQLlite是一個不需要安裝的本地端資料庫,不少的app也都會運用到它!
在python中也是一直內建的lib,直接import sqllite3就可以使用了!

之前在讀mis2000老師的書(asp.net)的時候,老師說的很清楚也簡單,資料庫的使用來來去去就是那幾招『connection、open、cmd、close』,這心法,我僅記在心不敢有忘。

在sqllite這邊也是一樣的。
import sqllite3

def sql_Createdb(dbname,sqlcmd):
    conn = sqllite3.connect(dbname)
    c = conn.cursor()
    c.execute(sqlcmd)
    conn.commit()
    conn.close()

if __name__ == '__main__'
    db_name = 'python'  #  預計建置的db名稱
    cmd = 'create table tablename (id integer primarty key autoincrement,cell1 text,cell2 integer,cell3 text)'
    sql_Createdb(db_name,cmd)

這樣子就可以直接去建置一個資料庫跟資料表了!

如果是要select的話
def sql_Selectdb(dbname,sqlcmd):
    conn = sqllite3.connect(dbname)
    c = conn.cursor()
    c.execute(sqlcmd)
    rows = c.fetchall()
    conn.close()
    return rows
以select的話,會回傳資料,所以會把整個rows拋回來給前端!
這時候再透過迴圈,就可以處理回來的資料了!
cmd = 'select * from  tablename'
for row in sql_Selectdb(dbname,cmd):
    print(row)

當然你也可以透過讀取csv檔去把csv檔的資料一次寫入sqllite
with open('xxx.csv', 'r', encoding='依實際格式') as f:
    reader = csv.DictReader(f)
    for row in reader:
        cmd = 'insert into xxx (a, b, c) values ("%d","%s","%s") ' % (row[xx],row[xx],row[xx])
        sql_Createdb(dbname_cmd)

簡單說明!

Python邊學邊記錄-csv與with open

Python csv、with open

處理資料免不了要保存下來,存成『JSON』或是『CSV』都是選項!
lib部份,記得要import csv!

假如我們已經把資料保存在一個list內了。
items = []

with open('abc.csv', 'w', encoding='utf-8', newline='') as f:
    writer = csv.writer(f)  #  建立一個寫入物件
    writer.writerow(('a', 'b', 'c'))  #  標題欄
    for item in items:
        writer.writerow((column for column in item))

with open的部份是python內的標準io模組的method。
第一個字串參數要新增或是處理的檔案名稱,範例為abc.csv
第二個字串參數是處理模式:
  • r讀取
  • w寫入(建立新檔或覆蓋原檔)
  • a附加在尾端
  • x寫入(建立新檔,若檔名存在即報錯)
  • t文字模式
  • b二進位模式
  • r+更新(檔案需存在,從頭開始讀寫)
  • w+更新(建立新檔或覆蓋,從頭開始讀寫)
  • a+更新(建立新檔或從舊檔尾端做讀寫)
第三個字串參數是編碼格式,這部份需視你爬的網頁格式。
第四個字串參數是換行符號

如果要取讀csv檔的話
with open('ezprice.csv', 'r', encoding='utf-8') as f:
    reader = csv.DictReader(f)  #  建立一個讀取物件
    for row in reader:
        print(row['a'], row['b'], row['c'])


Python邊學邊記錄-html encoding

Python html encoding


在部份網頁查詢的時候會發現,怎麼你查的字送出去的時候會變怪怪的碼!
html encoding
如上圖所示,搜尋了『小baby 推車 ip』,網址上多了不少『%』,這是因為被轉成了html encoding。
所以,在python處理的時候,就需要轉了以後再送出去,這樣子要爬的話才有辦法符合!

需求套件是『urllib.parse』。
透過cmd來做簡單的測試:
html encoding
接著,我們把取得的html encoding貼到網址去確認:
html encoding

Python邊學邊記錄-Crawler網路爬蟲-第八課-創建目錄與下載圖片

Python Crawler

在爬文章的過程中,我們會遇到想要的圖片要下載下來,像是捷克漫畫版如果有新的連載上來了,一定會癢癢的,或是表特版的正妹也是。

這時候要處理的還是怎麼去判斷這個連結是不是我們要的連結,就是又要靠正則式了!

基本上,主程式碼的部份都跟之前的相去不遠,只是多了幾個function處理新增的功能。

取得所有文章列表之後開始做後面的工作
for article in articles:
    page = get_articles(ptt_url + article['href'])
    if page:
        img_urls = parse(page)  #  這邊主要要取得圖片的連結
        saveImage(img_urls, article['title'])  #  這邊要保存圖片

接著要處理文章內的圖片連結(這個要視圖床,較多人在ptt分享都是透過imgur.com。
def parse(dom):
    soup = BeautifulSoup(dom, 'html.parser')
    links = soup.find(id='main-conetent').find_all('a')
    imgurls = []
    for link in links:
        if re.match(r'^https?://(i.)?(m.)?imgur.com',link['href']):
            imgurls.append(link['href'])
    return imgurls

最後就是把連結的資料拉下來了!
def saveImage(img_urls, title):
    if img_urls:
        try:
            dname = title.replace('?', '').replace('', '').replace(' ', '') 
            .replace('Re:', '').strip()  #  strip() 去除字串前後的空白            os.makedirs(dname)  #  創建資料夾
            for img_url in img_urls:  #  主要是把下載連結的格式再調整
                if img_url.split('//')[1].startswith('m.'):
                    img_url = img_url.replace('//m.', '//i.')
                if not img_url.split('//')[1].startswith('i.'):
                    img_url = img_url.split('//')[0] + '//i.' + img_url.split('//')[1]
                if not img_url.endswith('.jpg'):
                    img_url += '.jpg'                fname = img_url.split('/')[-1]
                urllib.request.urlretrieve(img_url, os.path.join(dname, fname))
        except Exception as e:
            print(e)

這邊記得要import os與urllib.request

Python邊學邊記錄-Crawler網路爬蟲-第七課-取得IP國家

Python Crawler

在第六課的時候,我們已經成功的取得了PTT的文章了,但是這樣還不夠,如果可以的話,我們還想取得這發文IP來源是那一個國家,或者是記下這個IP來查詢,到底那幾個帳號是從同一個IP出來就可以分出這是不是住一起的,或是分身帳號!

如果要查詢國家的話,可以透過http://freegeoip.net/json/網址或是ip來做查詢!
這是一個免費查詢ip國家的服務,每小時可以有15000次的查詢額度。

freegeoip回傳json格式如下:
freegeoip


我們在取得文章列表之後,寫入了articles這個list內,
country_to_count = dict()
for article in articles:
    print('文章IP:', article['title'])
    page = get_articles(ptt_url + article['href'])
    if page:
        ip = get_ip(page)
        country = get_country(ip)
        if country in country_to_count.keys():
            country_to_count[country] += 1        else:
            country_to_count[country] = 1

單純的迴圈計算出現在touple內出現的次數,若是沒有出現就給值『1』

get_ip的部份如下:
def get_ip(SoureceIP):
    reIP = '來自: \d+\.\d+.\d+.\d+'  #  這是把頁面內的發文ip取出的正則式
    match = re.search(reIP,SourceIP)  #  確認文章內是否有相對應的格式
    if match:
        return match.group(0).replace('來自: ','')  #  回傳第一個,另外也取代掉『來自: 』
    else:
        return None

取回ip之後,就丟給freegeoip去回傳json
def get_country(ip):
    if(ip):
        data = json.loads(request.get('http://freegeoip.net/json/' + ip).text)
        countryName = data['country_name'] if data['country_name'] else None
        return countryName 
    return None

因為有用到json.loads,記得要import json!
大概就是這樣了。









正則式學習記錄-Regular Expression

Regular Expression

網址:

範例:

來自: 123.456.789.000

Regular Expression:

/來自: \d+\.\d+\.\d+\.\d

說明:

『/』起始於『來自:』
『\d+』多個數字
『\.』點是特殊字元,所以要加一個斜線
就是,起始於『來自: 』『多個數字』『點多個數字』『點多個數字』『點多個數字』

範例:

取字串中的金額
<span class="price"><span class="currency">TWD</span> 1,118,043.00<br/></span>

Regular Expression:

\d{1,3}(,\d{1,3})*(\.\d{2})

說明:

『\d{1:3}』數值1到3位數
『,\d{1,3})*』,開頭,然後數值1到3位數,『*』比對前面的出現幾組我不確定
『(\.\d{2})』句點,然後數值2位數

2017年6月6日 星期二

Google Analytics學習筆記-初探

Google Analytics

分析大綱

  • 目標對象
    • 訪客的形貌
      • 裝置、地區、性別、年齡層、性別、興趣
  • 客戶開發
    • 流量來源
      • 自然搜尋、關鍵字廣告、社群、展示廣告
  • 行為
    • 訪客在站內幹嘛
      • 看那些頁面、觸動那些互動
  • 轉換
    • 預期目標的成效
      • 完成交易、瀏覽某特定頁面、特定的互動

指標判讀


  • GA搜集的指標約一百多種,可透過自訂報表來設置。

  • 新工作階段
    • 俗稱流量、造訪數、人次
  • 單次工作階段頁數
    • 平均的瀏覽頁數
  • 平均工作階段時間長度
    • 停在網頁上的時間
    • 只看一頁的情況下,平均停留時間在GA的定義為0
  • 跳出率
    • 只看一頁就離開,佔總造訪數的比率
    • 一頁式網站可透過事件設定,讓訪客跟網站互動之後,就可以有效區隔
      • 如網頁下拉、按下按鈕之類

用戶來源判斷

  • organic
    • 在搜尋引擎上透過搜尋過來的
  • referral
    • 透過其它網站連結過來的
  • direct/none
    • 直接打上網址過來的或是所有GA無法判斷的流量都會是算在這的
  • 自訂廣告活動
    • 可於網址後自訂來源參數
      • 來源source
      • 媒介medium
      • 廣告活動campaign
      • 廣告內容content
      • 關鍵字term
    • 語法
      • www.abc.com.tw/index.html/
        • ?utm_source=用戶自訂參數
        • &utm_medium=用戶自訂參數
        • &utm_campaign=用戶自訂參數
        • &utm_content=用戶自訂參數
        • &utm_term=用戶自訂參數
      • 參數由用戶自訂
      • 可細到從臉書那個貼文連結過來的也可以記錄
      • 透過不同地點的qrcode來做區隔連結也可以
      • 可透過ga help來搜尋url builders<-連結

GA-轉換

  • 目標類別
    • 電子商務目標
      • 還要另外上套件,記錄整個交易金額
    • 非交易型目標
      • 網頁目標
        • 訪客到了那個特定網頁即達標
      • 停留時間目標
        • 停留時間到了即達標
      • 瀏覽頁數目標
        • 頁數到了即達標
      • 事件互動目標
  • 目標價值
    • 電子商務目標
      • 以交易金額為目標
      • 單次造訪不管達成幾次,每次都算達標
    • 非交易目標
      • 自訂目標價值
      • 單次的造訪即使達成多次,也算一次達標
  • 如此即可將流量貢獻度給量化
  • 指標
    • 轉換數:達成次數
    • 轉換率:轉換數/造訪數
    • 轉換價值:交易金額/轉換價值

其它

  • 三十分鐘沒有動作,GA即認定工作階段結束
    • 這部份是可以調整的
  • 其它分析工作將新訪客稱為『UV』,唯GA定義為『USERS』
  • 可透過目標對象\行為\新訪客與回訪客來判斷新舊客戶數

2017年6月5日 星期一

藤原栗子週末碎念-0605

時間在走真的是不留一點情面,不知不覺就要領前東家的最後一份薪水了!

今天去了太陽能廠面試,面試官對於在前東家可以集團系統五個月上線感到非常不可思議...
呵,該說自己也有成就感嗎?

也很意外,太陽能廠把資訊切的這麼多組,ERP跟WMS、BPM跟報表、CIM跟MES、系統管理、系統開發,每組又各五到六人!

在前東家是300/6=50
這廠是1500/30=50

其實平均服務人數倒數也沒差多少,只是太陽能廠的ERP也要ON CALL就讓我意外了。
希望有好的開始!
週五封測廠的MES工程師加油了!


2017年6月1日 星期四

Python邊學邊記錄-Crawler網路爬蟲-第六課-PTT文章爬取

Python Crawler

ptt的sex版,每日每夜都有廢文產生,有時候沒有跟到的話,就只能500P求圖!
這時候就可以放著自動去爬了..

透過網頁版去登入的時候會發現,需要滿18才可以進去!
Python Crawler

這時候可以透過開發工具發現,client端送了一個cookie『over18=1』給了server!
Python Crawler

所以我們就可以利用這點來讓server相信,我們滿18了!
我們在透過requests.get的時候,就可以送個訊息給server端了:
resp = requests.get(
    url=url,    cookies={'over18': '1'}
)

再來就是要先確認,我們需要那些資訊!
Python Crawler

流程的部份:
我們登入首頁(此時是最新文章)->記錄上頁連結->確認有無本日文章->回到上頁->確認有無本日文章...如此迴圈!
PYTHON crawler
需求套件:
import requests
import time
import json
from bs4 import BeautifulSoup

公用變數:
ptt_url = 'https://www.ptt.cc' # 保留以後可以變數帶入其它板的機會

主程式的部份:

def __name__ == '__main__':
    connect_page =  checkStatus(ptt_url + '/bbs/sex/index.html') #確認網頁狀態是否正常
if connect_page:
        articles = [] #用來記錄文章list
        today = time.strftime("%m/%d").lstrip('0') #今天日期格式調整,time是import的模組
        today_articles,pre_url = get_articles(connect_page,today) #呼叫爬蟲fucntion
        # 到上面,已經可以爬到主頁上的文章了!
        # 爬完了之後,要進入驗證的迴圈,確認有無其它本日文章!
        while today_articles: #確認有無本日文章,如果list回來已經沒有東西了,那就代表沒有了!
            articles += today_articles #把爬回傳的list先寫丟進去主list
            connect_page = checkStatus(pre_url) #一樣需要做網頁狀態驗證
            today_articles,pre_url = get_articles(connect_page,today) #再呼叫爬蟲!







checkStatus(url):
# 主要確認網頁是否正常
def checkStatus(url):
    resp = requests.get(
        url = url,
        cookies = {'over18':'1'}
    )
    if resp.status_code != 200: #如果網頁狀態不存活了,就直接return None
        return None
    else:
        return resp.text

get_articles():
# 資料爬取的主要程式
def get_articles(respText,date): #一個是resp拋過來的資料,一個是今日的日期。
    soup = BeautifulSoup(respText,'html5lib')
    #取得網頁的上頁連結
    pre_div = soup.find('div','btn-group btn-group-paging')
    pre_url = pre_div.find_all('a')[1].href
    
    articles = [] #用來記錄文章list
    divs = soup.find_all('div','r-ent') #ptt的文章,都放在class是r-ent上!
    for d in divs:
        if d.find('div','date').text.strip() == date: #確認日期跟今天的日期是否相同
            #取得推文數
            pushCount = 0
            pushStr = d.find('div','nrec').text
            #因為推文有時候會是『X』被噓爆,或是『爆』被推爆,所以要特別處理。
            if pushStr:
                try:
                    pushCount = int(pushStr) #字串轉數字
                except ValueError:
                    if pushStr =="爆":
                        pushCount=99
                    elif pushStr.startswith('X'):
                        pushCount=-10

            #取得文章連結跟標題
            #這邊可以依需求自取,甚至可以再另外寫一個function去爬發文者的ip來做記錄!
            #後面可以利用那發文ip來比對id,就知道誰有什麼分身了...
            if d.find('a'): #有超連結就代表文章還活著,沒有被d掉。
                href = d.find('a').href #連結
                articleTitle = d.find('a').text #標題
                author = ''
                articles.append({
                    'title':articleTitle,
                    'href':href,
                    'author':author,
                    'pushCount':pushCount
                })
    return articles,pre_url

以上!
後續再來加追去取得發文者ip!