swire_docker_itemlist.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436
  1. # -*- coding: utf-8 -*-
  2. #from selenium import webdriver
  3. from seleniumwire import webdriver
  4. from selenium.webdriver.common.action_chains import ActionChains
  5. from selenium.webdriver.common.keys import Keys
  6. from selenium.webdriver.support import expected_conditions as EC
  7. from selenium.webdriver.support.wait import WebDriverWait
  8. from selenium.webdriver.common.by import By
  9. import selenium
  10. import traceback
  11. from datetime import datetime
  12. import dataset
  13. import time
  14. import json
  15. import re
  16. import sys, os
  17. import socket
  18. import brotli
  19. from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
  20. import urllib.parse
  21. #chrome_window=False
  22. chrome_window=True
  23. globalkw=None
  24. proxyport=8787
  25. def build_cache(db):
  26. id_dict={}
  27. cursor = db.query('SELECT place_id FROM google_poi.swire_store_list;')
  28. for c in cursor:
  29. id_dict[c['place_id']]=1
  30. return id_dict
  31. #
  32. def brower_start(port):
  33. global proxyport
  34. global chrome_window
  35. print(proxyport)
  36. options = webdriver.ChromeOptions()
  37. if chrome_window:
  38. options.add_argument('--ignore-certificate-errors')
  39. options.add_argument("--no-sandbox")
  40. options.add_argument("--headless")
  41. options.add_argument("--disable-gpu")
  42. options.add_argument("--disable-dev-shm-usage")
  43. browser = webdriver.Chrome(
  44. options=options
  45. # desired_capabilities=options.to_capabilities()
  46. )
  47. else:
  48. chrome_options = webdriver.ChromeOptions()
  49. chrome_options.add_argument('--proxy-server=host.docker.internal:'+str(proxyport)) # Specify your Kubernetes service-name here
  50. chrome_options.add_argument('--ignore-certificate-errors')
  51. chrome_options.add_argument("--no-sandbox")
  52. chrome_options.add_argument("--disable-dev-shm-usage")
  53. browser = webdriver.Remote(
  54. command_executor='http://127.0.0.1:'+str(port)+'/wd/hub',
  55. desired_capabilities=chrome_options.to_capabilities(),
  56. seleniumwire_options={'addr':'0.0.0.0','port':proxyport,'auto_config': False}
  57. )
  58. # seleniumwire_options = {'addr': '172.17.0.2','port':4444})
  59. browser.set_window_size(1400,1000)
  60. return browser
  61. def page_down_(driver, xpath_css, time_):
  62. e = driver.find_element_by_css_selector('span[class="Jl2AFb"]')
  63. result_count = e.text.split('-')[1].replace(' 項結果','')
  64. print(result_count)
  65. if int(result_count) > 5:
  66. for i in range(time_):
  67. e = driver.find_elements_by_css_selector('div[class="TFQHme"]')
  68. action = webdriver.common.action_chains.ActionChains(driver)
  69. action.move_to_element_with_offset(e[-1], e[-1].size['width'] + 1 , 0)
  70. action.click()
  71. action.perform()
  72. time.sleep(0.5)
  73. def get_url_list(driver):
  74. page_down_(driver, '//div[@class="TFQHme"]', 8)
  75. url_soup = BeautifulSoup(driver.page_source, 'html.parser')
  76. url_list = []
  77. for i in url_soup.find_all('a'):
  78. try:
  79. if i['href'].find('maps/place') != -1:
  80. url_list += [[i['href'], i['aria-label']]]
  81. except:
  82. pass
  83. # print(len(url_list))
  84. return url_list
  85. def keyin_keyword(driver, keyword):
  86. button = driver.find_element_by_id("searchbox")
  87. driver.implicitly_wait(30)
  88. ActionChains(driver).move_to_element(button).send_keys(keyword).send_keys(Keys.RETURN).perform()
  89. time.sleep(3)
  90. def scan_job(db,kw):
  91. result={'kw':kw}
  92. cursor = db.query('select t1.num,next-prev as diff from google_poi.conv_log t1, (SELECT num,max(id) mid FROM google_poi.conv_log group by num ) t2 where t1.id=t2.mid having diff>0 order by rand()')
  93. for c in cursor:
  94. result['num']=c['num']
  95. break
  96. cursor = db.query('select lat,lon,loc from lat_lon_loc where num ="'+str(result['num'])+'"')
  97. for c in cursor:
  98. result['lat']=c['lat']
  99. result['lon']=c['lon']
  100. result['loc']=c['loc']
  101. return result
  102. def get_next_job(db,repeat=False,repkw=None,repnum=None):
  103. global globalkw
  104. result={}
  105. # if globalkw is not None:
  106. # cursor = db.query('select distinct(kw),num+1 as num from swire_progress_list where kw="'+globalkw+'"')
  107. # else:
  108. # cursor = db.query('select distinct(kw),num+1 as num from swire_progress_list where num < 367 order by rand() limit 1')
  109. # cursor = db.query('select kw,num from areacodes where expand=0 order by rand()')
  110. cursor = db.query('select kw,num from areacodes order by rand()')
  111. for c in cursor:
  112. # repkw=c['kw']
  113. if repkw is None:
  114. repkw=c['kw']
  115. result['kw']=c['kw']
  116. result['num']=c['num']
  117. break
  118. if repkw is not None:
  119. result['kw']=repkw
  120. if result.get('num') is not None:
  121. cursor = db.query('select lat,lon,loc from lat_lon_loc where num ="'+str(result['num'])+'"')
  122. for c in cursor:
  123. result['lat']=c['lat']
  124. result['lon']=c['lon']
  125. result['loc']=c['loc']
  126. break
  127. if repeat and repkw!= 'REP':
  128. result['kw']=repkw
  129. result['num']=repnum
  130. if 'REP' in repkw:
  131. if repnum=='REP':
  132. repnum=None
  133. # cursor = db.query('select num from swire_store_list where num not in (select num from conv_log) order by rand() limit 1')
  134. cursor = db.query('select num from swire_store_list order by rand() limit 1')
  135. for c in cursor:
  136. repnum=c['num']
  137. break
  138. if repnum is None:
  139. cursor = db.query('select num from swire_store_list order by rand() limit 1')
  140. for c in cursor:
  141. repnum=c['num']
  142. break
  143. # cursor = db.query('select lat_txt,lon_txt,keyword,num from swire_store_list order by rand() limit 1')
  144. cursor = db.query('select lat_txt,lon_txt,keyword,num from swire_store_list where num="'+str(repnum)+'" limit 1')
  145. for c in cursor:
  146. result['kw']=c['keyword']
  147. result['num']=c['num']
  148. result['lat']=c['lat_txt']
  149. result['lon']=c['lon_txt']
  150. result['loc']=''
  151. return result
  152. if repeat:
  153. # cursor = db.query('select lat_txt,lon_txt from swire_store_list where num ="'+str(result['num'])+'" and keyword="'+result['kw']+'" order by rand() limit 1')
  154. cursor = db.query('select lat_txt,lon_txt,keyword from swire_store_list order by rand() limit 1')
  155. for c in cursor:
  156. result['kw']=c['keyword']
  157. result['lat']=c['lat_txt']
  158. result['lon']=c['lon_txt']
  159. return result
  160. def write_to_file(jsobj,fname):
  161. import codecs
  162. fw=codecs.open(fname,'w','utf-8')
  163. fw.write(str(jsobj))
  164. fw.close()
  165. def parsing_js(orig):
  166. resultobj=[]
  167. content=""
  168. lines=orig.split('\n')
  169. for l in lines:
  170. newl=l.replace('\\"','"')
  171. # if '\\\\"' in newl:
  172. # print(newl)
  173. # newl=newl.repace('\\\\"','')
  174. newl=newl.replace('\\"','"')
  175. content+=newl
  176. result=re.search(r'\[\["',content)
  177. print(result)
  178. content_begin=result.start()
  179. result=re.search(r'\]\]"',content)
  180. print(result)
  181. content_end=result.end()
  182. jscontent=content[content_begin:content_end-1]
  183. # write_to_file(jscontent,'c:/tmp/debug.txt')
  184. jsobj=json.loads(jscontent)
  185. for x in jsobj[0][1][1:]:
  186. print(x[14][11])
  187. print(x[14][9])
  188. reviews_cnt=None
  189. photo=None
  190. rating=None
  191. biz_id=None
  192. loc_x=None
  193. loc_y=None
  194. addr_elmts=None
  195. tel=None
  196. try:
  197. rating=x[14][4][7]
  198. reviews_cnt=x[14][4][8]
  199. except:
  200. traceback.print_exc()
  201. try:
  202. photo=x[14][37][0][0][0]
  203. num_photos=x[14][37][0][0][6][1]
  204. except:
  205. traceback.print_exc()
  206. try:
  207. loc_x=x[14][37][0][0][29][0]
  208. loc_y=x[14][37][0][0][29][1]
  209. except:
  210. traceback.print_exc()
  211. try:
  212. biz_id=x[14][57][2]
  213. tel=x[14][178][0][3]
  214. except:
  215. traceback.print_exc()
  216. try:
  217. addr_elmts=str(x[14][82])
  218. except:
  219. traceback.print_exc()
  220. category=str(x[14][13])
  221. topic=str(x[14][89])
  222. print(x[14][13])
  223. print(x[14][10])
  224. print(x[14][2])
  225. print(x[14][78])
  226. try:
  227. resultobj.append({'name':x[14][11],'fid':x[14][10],'addr':x[14][2][0],'addr_elmts':addr_elmts,'place_id':x[14][78],'category':category,'rating':rating,'reviews_cnt':reviews_cnt,'lat':x[14][9][2],'lat_txt':str(x[14][9][2]),'lon':x[14][9][3],'lon_txt':str(x[14][9][3]),'topic':topic,'photo':photo,'num_photos':num_photos,'loc_x':loc_x,'loc_y':loc_y,'biz_id':biz_id,'tel':tel,'crawler_date':datetime.today().strftime("%Y/%m/%d %H:%M")})
  228. except:
  229. traceback.print_exc()
  230. return resultobj
  231. def save_js_to_db(jsobj,num,keyword):
  232. global store_list_table
  233. global iddict
  234. for r in jsobj:
  235. if iddict.get(r['place_id']) is not None:
  236. continue
  237. r['num']=num
  238. r['keyword']=keyword
  239. try:
  240. store_list_table.insert(r)
  241. # store_list_table.upsert(r,keys=['place_id'])
  242. except:
  243. traceback.print_exc()
  244. # store_list_table.upsert(r,keys=['place_id'])
  245. def process_web_request(db,driver,area_num,keyword):
  246. global prev_cnt
  247. # query = WebDriverWait(driver, 30).until(EC.presence_of_element_located((By.XPATH, '//button[@vet="19128"]')))
  248. time.sleep(0.8)
  249. time.sleep(3)
  250. print("ppppppppp&**********************")
  251. for request in driver.requests:
  252. if 'search?' in request.url :
  253. print('searching.....')
  254. # else:
  255. # print(request.url[20:60])
  256. if request.response:
  257. # if 'https://www.google.com.tw/search?tbm=map' in request.url :
  258. if 'search?' in request.url :
  259. print('parsing js:')
  260. resp = brotli.decompress(request.response.body)
  261. jstext=resp.decode('utf-8')
  262. resultobj=parsing_js(jstext)
  263. print("before",datetime.now())
  264. print("num: "+str(area_num))
  265. save_js_to_db(resultobj,area_num,keyword)
  266. print("after",datetime.now())
  267. aft_cnt=0
  268. cursor = db.query('select count(*) as cnt from swire_store_list where num="'+str(area_num)+'" ')
  269. for c in cursor:
  270. aft_cnt=c['cnt']
  271. break
  272. db['conv_log'].insert({'num':area_num,'prev':prev_cnt,'next':aft_cnt,'dt':datetime.now()})
  273. # time.sleep(9999)
  274. def main():
  275. global chrome_window
  276. global store_list_table
  277. global globalkw
  278. global proxyport
  279. global iddict
  280. global prev_cnt
  281. port=4444
  282. # if len(sys.argv) == 3 :
  283. # port=int(sys.argv[1])
  284. # proxyport=int(sys.argv[2])
  285. if len(sys.argv)>1:
  286. globalkw=sys.argv[1]
  287. port=int(sys.argv[2])
  288. proxyport=int(sys.argv[3])
  289. print(globalkw, port, proxyport)
  290. failcnt=0
  291. localip=socket.gethostbyname(socket.gethostname())
  292. # if localip=='192.168.1.108':
  293. # chrome_window=True
  294. # chrome_window=False
  295. db = dataset.connect('mysql://choozmo:pAssw0rd@db.ptt.cx:3306/google_poi?charset=utf8mb4')
  296. iddict=build_cache(db)
  297. store_list_table = db['swire_store_list']
  298. # table2 = db['swire_progress_list']
  299. table2 = db['swire_area_progress']
  300. if not chrome_window:
  301. print('restart docker p{}'.format(port))
  302. # os.system('sudo docker container restart p'+str(port))
  303. os.system('docker container restart p'+str(port))
  304. time.sleep(10)
  305. print('drvier start...')
  306. driver = brower_start(port)
  307. area_num=None
  308. while True:
  309. try:
  310. if len(sys.argv) > 4 :
  311. repkw=sys.argv[1]
  312. repnum=sys.argv[2]
  313. if 'SCAN' in repkw:
  314. job=scan_job(db,repnum)
  315. else:
  316. job=get_next_job(db,repeat=True,repkw=repkw,repnum=repnum)
  317. else:
  318. job=get_next_job(db, repkw=globalkw)
  319. print(job)
  320. keyword = job['kw']
  321. latitude = job['lat'] #緯度
  322. longitude = job['lon'] #精度
  323. area_num=job['num']
  324. safe_string = urllib.parse.quote_plus(keyword)
  325. url = 'https://www.google.com.tw/maps/@{},{},18z?hl=zh-TW'.format(latitude, longitude)
  326. prev_cnt=0
  327. cursor = db.query('select count(*) as cnt from swire_store_list where num="'+str(area_num)+'" ')
  328. for c in cursor:
  329. prev_cnt=c['cnt']
  330. break
  331. # url = 'https://www.google.com/maps/search/'+safe_string+'/@{},{},16z/data=!3m1!4b1'.format(latitude, longitude)
  332. # url='https://www.google.com/maps/search/'+safe_string+'/@24.7962279,121.0449762,15z/data=!3m1!4b1?hl=zh-TW'
  333. # print(url)
  334. # url='https://www.google.com/maps/search/%E7%81%AB%E9%8D%8B%E9%A4%90%E5%BB%B3/@24.772608,121.0515456,13z'
  335. driver.get(url)
  336. # time.sleep(3)
  337. keyin_keyword(driver, keyword)
  338. process_web_request(db,driver,area_num,keyword)
  339. pagecnt=0
  340. while True:
  341. element = driver.find_element_by_id('ppdPk-Ej1Yeb-LgbsSe-tJiF1e')
  342. if element.get_attribute('disabled'):
  343. break
  344. # driver.implicitly_wait(30)
  345. ActionChains(driver).move_to_element(element).click(element).perform()
  346. process_web_request(db,driver,area_num,keyword)
  347. pagecnt+=1
  348. if pagecnt>=5:
  349. break
  350. # table2.upsert({'kw':keyword,'num':job['num']},['kw'])
  351. table2.insert({'kw':keyword,'num':job['num']},['kw'])
  352. db.query('update areacodes set expand = 1 where num="'+str(job['num'])+'" and kw="'+keyword+'" ')
  353. except:
  354. traceback.print_exc()
  355. failcnt+=1
  356. if failcnt>=15:
  357. sys.exit()
  358. pass
  359. if __name__ == '__main__':
  360. main()