分類
程序

豆瓣相册自动翻页

從台灣旅行回來,Emanon又往豆瓣相冊里上傳了很多照片。這些照片是經過她篩選的,所以質量比較高,一張一張看一遍也很舒服。但是一張一張看,手很累,即使豆瓣貼心的準備了右鍵翻頁功能。於是我就想通過網絡控制台的js來讓網頁自動跳轉,最後發現網頁控制台的代碼只能在當前網頁執行一次,到了新網頁就不能自動運行了。然後看了下火狐的擴展幫助,感覺還挺方便的於是,提交了個自動翻豆瓣相冊的插件。插件安裝地址:豆瓣相册自动翻页

當前版本安裝後只是匹配到照片頁面後,就傻瓜等待5秒後,點擊下一頁,沒有配置項,所以不用時需要去火狐的擴展頁面禁用此擴展。

以後有空的話會完善一下,增加自定義時間和手動啟動的功能。

本文更新於 2016/10/20。

分類
程序

蛋國志

蛋國志

Emanon目前呆過福利最好的公司的遊戲終於公測了!蛋國志Facebook蛋國志谷歌市場。投放谷歌市場時應該鎖了區,所以大家可以通過APKPure搜索包名com.koogame.eggworld.ganpu01並選擇馬來西亞區進行下載體驗。

我的感覺是,遊戲很萌!蛋蛋們很可愛又各有特點,配樂也很有意思,作為遊戲,各個角色的配比也比較用心,總之還是很值得玩一玩的。我覺得萌度已經達到了The Battle Cats的高度,而且還比The Battle Cats耐玩,至少一開始是這樣。技能描述的小動畫我也很喜歡,藏的好深的。

蛋国志是一款有趣又有料的休闲竞技策略手游。耳熟能详的历史名将,变身创意有趣的蛋蛋人,来到独一无二的的蛋世界。

作为指挥官的你,要做的事情很简单,也很不简单!那就是:收集和培养你的英雄、搭配和调教你的阵容,努力成为最厉害的蛋国指挥官!

作为小编的我,小小剧透一下,在这个精彩有趣的蛋世界,包括但不限于的组合有: 关羽林冲姜子牙、荆轲黄忠诸葛亮、吕布貂蝉花木兰…各种奇葩各种组合,多人在线同场竞技,看看你的阵容谁能破?


新版本已經取消了鎖區,大家可以直接從谷歌市場下載玩耍了。而且上面提到的好玩的技能動畫現在只有在facebook才能看到,遊戲里還沒加上。另外告訴新手一個機密,能賣諸葛亮的時候趕緊買一個,保證一段時間內所向無敵!還有就是不充值並不影響遊戲體驗。


2017-06-15 時隔一年有新版本哦,新版有了新玩法和酷炫的皮膚,在酷市場下載蛋國志,在谷歌市場下載蛋國志。除了新增玩法和皮膚之外,人物的屬性似乎也有調整,當年法海加花木蘭加李白簡直天下無敵,現在要重新找個組合了。

本文更新於 2017/06/15。

分類
程序

定時發布

接口需要添加一個定時發布的功能,這樣可以提前準備好內容,時間一到,用戶就能看到。這裡用到js和php的日期操作。

大概搜了下html5中用datetime相關的表單,但是由於瀏覽器實現的問題,為了穩定性最終放棄。使用"YYYY-MM-DD HH:mm:ss"這樣的文本來保存設置時間,後台轉換成utc時間戳,最後通過對比時間戳來決定是否發布。時間全部顯示為北京時間。php使用了thinkphp框架。js和php默認返回的時間戳都是UTC時間。

後台的添加新聞模板:

<input type="text" class="" size="100" maxlength="300" name="publishTimeU" id="publishTimeU" value=""/>
<input type="hidden" maxlength="100" name="publishTime" id="publishTime" value=""/>
<script type="text/javascript">
(function($){
	var date = new Date();
	date = date.toISOString().substr(0, 19)+"-08:00";
	var date1 = new Date(date);
	date1 = date1.toISOString().substr(0, 19);
	date1 = date1.replace(/T/, " ");
	$("#publishTimeU").val(date1);
	
	//定時發布失去焦點時,換算時間戳
	$("#publishTimeU").blur(function(){
		var ptString=$("#publishTimeU").val();
		ptString=ptString.replace(/ /, "T")
		var pt=Date.parse(ptString+"+08:00")/1000;
		$("#publishTime").val(pt);
		
	}); 
})(jQuery);
</script>

後台的修改新聞模板:

<input type="text" class="" size="100" maxlength="300" name="publishTimeU" id="publishTimeU" value=""/>
<input type="hidden" maxlength="100" name="publishTime" id="publishTime" value="{$vo.publishTime}"/>
<script type="text/javascript">
(function($){
	var date = new Date($("#publishTime").val()*1000);
	date = date.toISOString().substr(0, 19)+"-08:00";
	var date1 = new Date(date);
	date1 = date1.toISOString().substr(0, 19);
	date1 = date1.replace(/T/, " ");
	$("#publishTimeU").val(date1);
	
	//定時發布失去焦點時,換算時間戳
	$("#publishTimeU").blur(function(){
		var ptString=$("#publishTimeU").val();
		ptString=ptString.replace(/ /, "T")
		var pt=Date.parse(ptString+"+08:00")/1000;
		$("#publishTime").val(pt);
		
	});
})(jQuery);
</script>

php接口:

$now = new DateTime(null, new DateTimeZone('Asia/Hong_Kong'));		
$nowTimestamp = $now->getTimestamp();
//只需在查詢語句的map里添加時間戳對比即可
$map = array (
	'h'		=> array('like','%'.$cid .'%'),
	'publishTime'	=> array('LT',$nowTimestamp),
	'status'	=> 1
);
$count = $model->where ( $map )->cache (false)->count ();
分類
程序

Emojiえもじ

Emoji即顏文字,現在還挺流行的,像?,完整表可以看Emoji Unicode Tables。其中第一列就是當前設備原生顏文字的表現形式。由於顏文字實際上是字符,所以不同平台有不同的展現形式,就像不同的字體一樣。如果想在網頁中加入顏文字,直接把顏文字當字符複製到網頁中就可以了。

最近用到一個功能,讓Line分享的信息中包含顏文字排列出的圖案,像這種
     ??     ??
???????
???????
???????
     ?????
          ???
               ?
問題主要在於空格和換行,空格無需處理,直接放到待分享信息中即可,換行用\n代替,就可把上面圖案傳至Line分享框了。Line的分享格式我是這樣寫的:

var shareMsg='好搞笑哦\n?';
function shareToLine42(){
	lineUrl="line://msg/text/"+encodeURIComponent(shareMsg)+"%0D%0Ahttps://ft.wupo.info/";
	//如果你有谷歌統計,下面一行可以統計按鈕的點擊次數
	//ga('send', 'event', 'button', 'click', 'share-line-button');
	window.open(lineUrl, 'sharer', 'toolbar=0,status=0,width=626,height=436');
}
注意,shareMsg中顏文字被wordpress做了修改,用來兼容沒有顏文字的平台,實際直接這樣寫"好搞笑哦\n?"就可以。後面代碼中再有顏文字我用"顏文字UTF8"代替。

在wordpress4.4中,顏文字是這樣展現的,把真正的utf8字符放到了alt標籤里。

<img class="emoji" draggable="false" alt="顏文字UTF8" src="https://s.w.org/images/core/emoji/72x72/1f602.png">
去數據庫發現posts表中post_content字段類型為longtext,排序規則為utf8mb4_unicode_ci。其中保存的就是?,而用圖片替換顏文字是發生在文章輸出過程中的。關於排序規則請參考:What's the difference between utf8_general_ci and utf8_unicode_ci,如果沒空細看,那麼結論是直接用utf8mb4_unicode_ci就好。如果你還在用utf8-general-ci,是無法儲存顏文字的。

本文更新於 2016/07/20。

分類
程序

python3字符串自增

週末喝恆大冰泉,發現掃二維碼中獎概率頗高,而且可以中獎金額直接用來給手機充值或提現到銀行卡,做的比較好。趁理髮無聊的時候寫了段python掃了一會兒,但是空手而歸。代碼也很簡單和用Python抓取大衆點評的用戶評論差不多,主要就是字符串自增這塊用了個遞歸:

from bs4 import BeautifulSoup import string,sys,time,random,urllib,http.cookiejar,socket #url="https://sao.so/t/dSTUVvjUhPHpz" baseDir="/storage/sdcard0/com.hipipal.qpyplus/scripts3/test/" base="_0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" HDcode="dSTUVvjUhPIjL" bingoNo=0 failNo=0 def increase(s): sHead=s[0:-1] sFoot=s[-1:] sNew="" if(sFoot != "Z"): index=base.index(sFoot) sFootNew=base[index+1] sNew=sHead+sFootNew else: sHeadNew=increase(sHead) sFootNew="_" sNew=sHeadNew+sFootNew return sNew def getHTML(url): request = urllib.request.Request(url) request.add_header("User-Agent", "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:37.0) Gecko/20100101 Firefox/37.0") try: response = urllib.request.urlopen(request) except (urllib.error.HTTPError, socket.error,urllib.error.URLError) as e: print('Connection error occurred when inserting data.'+str(e)) else: if response.code != 200: print("Error code:"+response.code) else: html = response.read().decode('utf-8') return html def check(html): global bingoNo global failNo #with open(baseDir+'expired.html',encoding='utf-8') as html: soup = BeautifulSoup(html) images = soup.find_all('img') for image in images: if "errorQrCode.jpg" in image.get('src') : failNo = failNo + 1 print("fake: " + HDcode + " " + str(failNo)) break elif "冰泉君已经失身啦" in soup.get_text(): print("expired" + HDcode) break else: print("bingo" + HDcode) bingoNo = bingoNo + 4 if __name__ == '__main__': #html=getHTML(url) #with open(baseDir+'fake.html', mode='w', encoding='utf-8') as html_file: #html_file.write(html) global HDcode while(bingoNo < 2): url = "https://sao.so/t/" + HDcode html = getHTML(url) check(html) HDcode = increase(HDcode) time.sleep(random.randrange(4,7)) [/code]

其實命中的概率真的非常低,拿13位編碼來說,一共有(11+26+26)^13=2.46*10^23種組合,瓶子上說中獎概率33.3%,按300億銷售目標和5元均價算,一共有2×10^10瓶是可以中獎的。除一下就發現……不用除了吧

分類
程序

用Python抓取大衆點評的用戶評論

大衆點評的知识产权声明可真是霸道啊!還是自己先保存一份。下面代碼先將評論及商戶保存到sqlite數據庫,如果需要還可以導出成CSV,這樣辦公軟件就能直接打開查看了。

from bs4 import BeautifulSoup
import sys,time,random,urllib,http.cookiejar,socket,sqlite3,csv


goOn=1
stopDate=''
UserID=''
review={'shopName':'','shopAddr':'','shopURL':'','reviewURL':'','star':'',
'starDetail':'','costPerPeople':'','reviewText':'','dishes':'','reviewTime':''}

def getHTML(url):
  print("Fetching "+url)
  request = urllib.request.Request(url)
  request.add_header("User-Agent", "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:37.0) Gecko/20100101 Firefox/37.0")
  try:
    response = urllib.request.urlopen(request)
  except (urllib.error.HTTPError, socket.error,urllib.error.URLError) as e:
    print('Connection error occurred when inserting data.'+str(e))
  else:
    if response.code != 200:
      print("Error code:"+response.code)  
    else:
      html = response.read().decode('utf-8')
      return html

def getList(url):
  global review,goOn
  reviewList=getHTML(url)
  soupAll = BeautifulSoup(reviewList).find_all("div",{"class":"txt J_rptlist"})

  for soup in soupAll:
    shopLink = soup.find("a",{"class":"J_rpttitle"})
    review['shopName']=shopLink.text
    review['shopURL']=shopLink.get("href")
    
    shopAddr = soup.find("p",{"class":"col-exp"})
    review['shopAddr']=shopAddr.text
    
    reviewID = soup.find("a",{"class":"J_flower aheart"})
    review['reviewURL']="http://www.dianping.com/review/"+reviewID.get("data-id")
    
    reviewDateDiv = soup.find("div",{"class":"mode-tc info"})
    reviewDateSpan=reviewDateDiv.find("span",{"class":"col-exp"})
    reviewDate=str(reviewDateSpan.text)[3:]
    if(len(reviewDate)==8 and reviewDate>stopDate):
      getReview(review['reviewURL'])
      #抓取頻率
      time.sleep(random.randrange(5,10))
    else:
      goOn=0
  if(goOn==0):
    print("Finished.")
    exit()
    
      
    

def save():
  global review,UserID
  conn = sqlite3.connect('DZDB_'+UserID+'_Reviews.db')
  c = conn.cursor()
  c.execute("""create table if not exists reviews (ID integer primary key not NULL,shopName char(50),shopAddr char(100),shopURL char(100),reviewURL char(100),star char(1),starDetail char(15),costPerPeople char(15),reviewText TEXT,dishes char(100),reviewTime char(20))""")
  s="""insert into reviews (ID,shopName,shopAddr,shopURL,reviewURL,star,starDetail,costPerPeople,reviewText,dishes,reviewTime) VALUES (NULL,\'"""+review['shopName']+'\',\''+review['shopAddr']+'\',\''+review['shopURL']+'\',\''+review['reviewURL']+'\',\''+str(review['star'])+'\',\''+review['starDetail']+'\',\''+review['costPerPeople']+'\',\''+review['reviewText']+'\',\''+review['dishes']+'\',\''+review['reviewTime']+'\')'
  c.execute(s)
  conn.commit()
  c.close
  print("Record at "+review['shopName']+" saved to Datebase.")
  review={'shopName':'','shopAddr':'','shopURL':'','reviewURL':'','star':'',
'starDetail':'','costPerPeople':'','reviewText':'','dishes':'','reviewTime':''}

def getReview(url):
  global review
  reviewHTML=getHTML(url)
  reviewAll=BeautifulSoup(reviewHTML)
  shopInfo= reviewAll.find("ul",{"class":"contList-info"})
  star=str(shopInfo.find("li"))
  if("msstar50" in star):
    review['star']=5
  elif ("msstar40" in star):
    review['star']=4
  elif ("msstar30" in star):
    review['star']=3
  elif ("msstar20" in star):
    review['star']=2
  elif ("msstar10" in star):
    review['star']=1
  else:
    review['star']=0
  starDetails=shopInfo.find_all("span",{"class":"rst"})
  starDetail=""
  for s in starDetails:
    s1=s.text[0:3]
    starDetail=starDetail+s1
  review['starDetail']=starDetail
  
  reviewText= reviewAll.find("div",{"class":"contList-con"})
  review['reviewText']=reviewText.text
  units= reviewAll.find_all("div",{"class":"comment-unit"})
  for unit in units:
    unit=str(unit.text).replace('\n','')
    if("人均:" in unit):    
      review['costPerPeople']=unit[4:]
    elif("喜欢的菜:" in unit): 
      unit=unit.replace(' ','')
      unit=unit.replace('\xa0',' ')
      review['dishes']=unit[7:]
    
  reviewInfo= reviewAll.find("ul",{"class":"contList-fn"})  
  reviewTime=reviewInfo.find("li")
  review['reviewTime']=reviewTime.text
  save() 

def main():
  fun=int(input("请输入数字选择功能:\n[1]抓取数据,[2]导出数据: \n"))
  if(fun==1):
    fetchReview()
  elif(fun==2):
    sqliteToCSV()
  else:
    print("请输入1或2。")

    
def sqliteToCSV():
  dbFile=str(input("请输入数据库文件名:\n"))
  with open(dbFile+'.csv','w+',newline='') as csvfile:
    spamwriter = csv.writer(csvfile)
    conn=sqlite3.connect(dbFile)
    c = conn.cursor()
    spamwriter.writerow(['ID','shopName','shopAddr','shopURL','reviewURL','star',
'starDetail','costPerPeople','reviewText','dishes','reviewTime'])
    for row in c.execute('SELECT * FROM reviews'):
      spamwriter.writerow(row)
    c.close()
    print("CSV文件成功導出。")
    
def fetchReview():
  #抓取参数:用户ID,起始页,结束日期
  global stopDate,UserID
  UserID=str(input("请输入您的大众点评ID,可以在您大众点评主页的网址中看到,如23262500:\n"))
  startPageNo=int(input("开始的页码,如1:\n"))
  stopDate=str(input("请输入评论结束日期(yy-mm-dd),如00-00-00:\n"))
  
  urlBase="http://www.dianping.com/member/"+UserID+"/reviews?pg="
  startPageNo=startPageNo-1
  while(goOn==1):
    startPageNo=startPageNo+1
    getList(urlBase+str(startPageNo))
    
if __name__ == "__main__":
    main()
幾點說明
  • 抓取頻率不要過大,否則大衆點評會屏蔽IP。我在抓取到20頁左右的時候碰到過一次屏蔽IP。如果意外中斷,你可以設置參數繼續下載,附w3school的SQL基礎教程
  • BeautifulSoup真是個好工具,連Qpython3都自帶了,但是遺憾的是這個代碼在Qpython3上跑報NoneType錯誤。
  • 我用了幾次都沒問題。
分類
程序

IP地址和歸屬地

移動2G網速好爛!看個IP歸屬地都要等好久。於是自己寫了個小小的php,輸出用不了1K數據,這樣既省流量又快速。代碼在Github:根據IP查看地理位置


//服務端獲取客戶端IP
$ip = getenv('HTTP_CLIENT_IP')?:
    getenv('HTTP_X_FORWARDED_FOR')?:
    getenv('HTTP_X_FORWARDED')?:
    getenv('HTTP_FORWARDED_FOR')?:
    getenv('HTTP_FORWARDED')?:
    getenv('REMOTE_ADDR');

本文更新於 2016/09/19。