2023年6月3日 星期六

[scrapy] 使用 scrapy 爬不到資料

Photo by ThisIsEngineering

記錄一下使用 scrapy 遇到的一些問題

問題:
用 browser 打開這個網頁明明就能看到畫面,但使用下面方法後
scrapy shell https://info.sogo.com.tw/tp1/floors/B2 
view(response)
卻只能看到下面錯誤

後來發現,這是因為少設定了 USER_AGENT 的關係,user agent 通常是用來識別 request 這方的軟體、os、device 等資訊,有些 server 會檢查這個 http header 資訊,若沒有的話,就不會回傳正確 response

處理方式:
在 settings.py 裡找到 USER_AGENT 設定,將一個正確的 user agent 填入即可,這邊我是參考 chrome 的 user agent 填入(如下)

問題:
網頁能打開後,卻找不到品牌列表,用 browser 打開往下 scroll 後,會看到如下的畫面,品牌列表的部份看起來是被放在這樣的結構裡

<div class="tab-content">
...
<a href="xxxx" class="brandBox">...</a>

但是使用
scrapy shell https://info.sogo.com.tw/tp1/floors/B2 
view(response)
卻只能看到 <div class="tab-content"> 裡沒有 brandBox 的資料

分析:
用 chrome 的 inspect 可以找到品牌列表是用這個 request 來的

而這個 request 是由 jquery-3.2.0.min.js 裡呼叫的
由此就能確定,找不到品牌列表是因為他是 javascript 的 request 而來的,scrapy 預設是爬靜態網頁,所以我邊需要針對這個 javascript 的 request 多做處理才行

這邊分享兩個 debug 技巧,
1. 在 spider 程式內呼叫 scrapy shell 的功能,在 def parse() 裡寫到下面即可
from scrapy.shell import inspect_response
inspect_response(response, self)
2. 在 spider 程式內印出 response 網頁資料,做法如下
def write_to_file(self, words):
    with open("logging.log", "a") as f:
        f.write(words)

def parse():
    self.write_to_file("response text: %s" % response.text)

處理方式:
使用 selenium 幫忙處理 javascript 的 request,照下面方法將 selenium 安裝且設定好,使用 selenium 的 function 做同一個 url 的 request,response 的資料裡就有品牌列表了
安裝 selenium
pip install scrapy-selenium
安裝 chrome driver
這裡下載跟自己使用的 chrome driver 相近的版本
在 settings.py 裡做好設定
總共四個設定,SELENIUM_DRIVER_EXECUTABLE_PATH 就是填上面下載的 chrome driver 檔案的路徑
在 spider 中使用
這邊不使用原本的 start_urls,而是使用如下的做法
from scrapy_selenium import SeleniumRequest
def start_request(self):
    target_url = "xxx"
    yield SeleniumRequest(url=target_url, callback=self.parse)

原本使用下面兩行去看有多少品牌是 0,設定成功之後,就可以看到 60
brands_num = len(response.xpath('//a[@class="brandBox"]'))
print("brands_num: " + (str)(brands_num))

Reference

2023年2月26日 星期日

[Web] 開源傳說小工具網頁版

Photo by Ben Taylor

在 [App] iOS 傳說小工具誕生以及網頁版結束維護 有提到,網頁版傳說小工具會想 open source,好讓有興趣的人可以繼續維護,現在完成開源了。

開源傳說對決網頁版
https://github.com/bradchow/toolsofrov_web

開源的程式碼原本是在 Heroku 上運作在 php 後台的,所以只要有 php 環境,放上這些檔案就可以直接使用,我只有把下面程式拿掉,然後加上一些 readme.md 和 LICENSE.md

1. Firebase
2. Google Analytics
3. Google Adsense

2023年1月20日 星期五

[App] iOS 傳說小工具誕生以及網頁版結束維護

Photo by Brett Jordan

網頁版傳說小工具使用的主機 Heroku,已經停止免費提供網頁服務了,傳說小工具一直以來的變現能力都不好,所以也不打算花錢買 Heroku 的服務,雖然網頁版傳說小工具就這樣畫上句點,但未來有打算將他 open source,讓有興趣的人可以繼續維護。

網頁版從 2017 年開始服務,當時還提到若要開發 iOS 版必定要花上很長一段時間,我一直沒有忘記這件事,工作緣故讓我必須多接觸 iOS 相關環境,這也正是我著手進行 iOS 版的契機,雖然變現能力不好,Apple Developer 的保護費費用也相當高(每年 100 美金),但在 Android Play Store 後台看到還是有不少人在使用,決定還是要完成這件事,2017 年推出了 Android 版,在經過了 5 年多之後,iOS 版傳說小工具終於上架了,同樣的,第一版功能還蠻陽春,讓我們慢慢改進

傳說小工具 App Store 連結
https://apps.apple.com/app/id1664793884

傳說小工具粉絲專頁
https://www.facebook.com/toolsofrov/


2022年12月31日 星期六

[投資] 2022 年投資回顧與未來展望

Photo by Engin Akyurt

2022 年使用了定期定額+再平衡的操作,已實現投報 1.87%,未實現投報 -20%,從台股大盤 -22%、NASDAQ -33% 看來,表現雖是有比大盤好,但這可能也代表大盤投報好的時候我的投報可能會落後。一個月操作一次的期望都有做到,花的時間也比以前再更少,過程跟績效都符合預期,就這麼繼續做下去吧。

2023 年的策略:定期定額 + 再平衡

定期定額:每個月操作一次,投入月 KD 較低的標的
再平衡:每月若有投報超過 20% 的標的以及每半年做整體再平衡

標的(與去年相同)

0050、00878、5880 合庫金、2412 中華電、QQQ、ARKW、AAPL、TSLA

最後附上 2022 年市值變化圖,資產還能往上的原因是,每個月都有持續投錢進來,只能說金額不多的時候,每個月的存錢會佔較高比例 XD,數字比例上比較好看





2022年12月26日 星期一

[Xcode] 升級 Xcode  後打不開專案 Could not open workspace file at xxx

舊版 Xcode 升級後,打開 Xcode 按下既有 project,遇到上面問題,莫名其秒

解法也不難,從 Finder 裡找到 project 位置,直接執行 <你的 project>.xcodeproj 就能打開了

2022年12月11日 星期日

[Android][App] 傳說小工具進版 targetSDKVersion 31 後遇到的問題

Photo by Malte Luk

這次進版問題特別多,就把這些過程都記錄下來,希望也幫助到遇到類似問題的人

這邊也帶出個問題,就是平常用的測試手機 HTC UU 是 Android 8 的版本實在太舊了,測不出問題 XD,話說現在還有人在用 Android 8 的手機嗎?

我的開發環境:Android Studio 3.6.1, Java

問題:
Targeting S+ (version 31 and above) requires that one of FLAG_IMMUTABLE or FLAG_MUTABLE be specified when creating a PendingIntent.
Strongly consider using FLAG_IMMUTABLE, only use FLAG_MUTABLE if some functionality depends on the PendingIntent being mutable, e.g. if it needs to be used with inline replies or bubbles.

有趣了,我的 source code 裡沒有用到 PendingIntenet,居然要我加 FLAG,後來才發現,原來是使用的 library 裡有用到...

處理方式:
發現 app 已經非常久沒使用,之前用的 library 都太舊了或無法使用,先改用 AndroidX 並將舊的 library 換掉

使用 AndroidX,參考 https://developer.android.com/jetpack/androidx?hl=zh-tw
gradle.properties
+android.useAndroidX=true
+android.enableJetifier=true

若有 library 因此找不到,可參考 https://developer.android.com/jetpack/androidx/migrate/class-mappings?hl=zh-tw 來替換

app\build.gradle
defaultConfig {
    -minSdkVersion 16
    +minSdkVersion 21
    +multiDexEnabled true
}
dependencies {
    +implementation 'androidx.work:work-runtime-ktx:2.7.0'
    +implementation 'androidx.work:work-runtime:2.7.1'
}

build.gradle
dependencies {
    -classpath 'com.android.tools.build:gradle:3.2.1'
    -classpath 'com.google.gms:google-services:3.2.0'
    +classpath 'com.android.tools.build:gradle:3.6.4'
    +classpath 'com.google.gms:google-services:4.3.14'
}

升級 gradle(利用 Android Studio 在 build 的時候的提示做的)

問題:
java.lang.NoSuchMethodError: No static method metafactory

處理方式:
build.gradle
android{
   compileOptions {
      sourceCompatibility JavaVersion.VERSION_1_8
      targetCompatibility JavaVersion.VERSION_1_8
   }
}

問題:
Error inflating class com.google.android.gms.ads.AdView

處理方式:
build.gradle
dependencies {
    -api 'com.google.android.gms:play-services-ads:11.8.0'
    +api 'com.google.android.gms:play-services-ads:21.3.0'
}
加入以下在 AndroidManifest.xml 裡
<meta-data
    android:name="com.google.android.gms.ads.APPLICATION_ID"
    android:value="ca-app-pub-xxxxxxxxxxxxxxxx~yyyyyyyyyy"/>

問題:
error: incompatible types: String cannot be converted to OnInitializationCompleteListener        MobileAds.initialize(this, "xxxx");

處理方式:
使用下面方式替換原有寫法
AdView mAdView = (AdView) findViewById(R.id.adView);        mAdView.setAdUnitId(getString(R.string.banner_ad_unit_id));


Reference
Firebase For Flutter Execution failed for task ':app:transformClassesWithDexForDebug'
feedbackGet started with Google Analytics




2022年12月3日 星期六

[生活] RHINOSHIELD 犀牛盾 固架的優缺




不斷從網頁和 YouTube 上看到 RHINOSHIELD 犀牛盾 固架的廣告,被它的便利性給吸引,不用黏在手機殼上,只要有 MagSafe,就可以在要用時吸上去就行,而且吸力超強,很適合我常遇到的一個情境,就是在吃飯時,手機只能平放在桌上,很不適合邊吃邊看,所以就買回來試試了

優點:
1. 吸力確實超強不怕掉
2. 手機直立使用時確實能讓你在吃飯時看手機有個好角度,手機跟桌面的角度大概在 111 度

缺點:
1. 手機平放使用時,手機跟桌面的角度大概在 98 度左右,這樣的角度使用起來有點太小,還是能使用但若角度再大一點會更好
2. 搭配 iPhone 12 Pro Max 直立使用時,站立時不太穩定,手機很容易會晃動

上面的角度是我使用 Angle Meter 這個 app 量測出來的,可能沒到很精確,但可以參考一下。