Crawler_controller.py 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527
  1. from selenium import webdriver
  2. import threading
  3. import time
  4. from os.path import exists
  5. from os import mkdir
  6. import hashlib
  7. from time import sleep
  8. import bs4
  9. class URL_PAGE():
  10. def __init__(self,url,func='get'):
  11. self.url = url
  12. self.func = func
  13. def __str__(self):
  14. return self.url
  15. class url:#url管理器
  16. num = 0#url处理器个数
  17. def __init__(self,dic=f'',dic_run=f''):
  18. url.num += 1
  19. dic += f'/url[{url.num}].cot_url'
  20. dic_run += f'/url_run[{url.num}].cot_url'
  21. self.dir = dic
  22. self.dir_run = dic_run
  23. self.file = open(dic,'a')#写入url_history的文件
  24. self.file_run = open(dic_run,'a')#写入已读url文件
  25. self.url_list = []#待读url
  26. self.url_history = []#url历史
  27. self.filter = {}#过滤函数
  28. def filter_func(self,url):#url过滤系统
  29. for i in self.filter:
  30. if not self.filter[i](url): return False
  31. return True
  32. def Add_func(self,func,name):#添加过滤函数
  33. self.filter[name] = func
  34. def Del_func(self,index):#删除过滤函数
  35. del self.filter[list(self.filter.keys())[index]]
  36. def return_func(self):
  37. return list(self.filter.keys())
  38. def add_url(self,url):#添加url
  39. if url not in self.url_history and self.filter_func(url):#1.url不存在历史,2.url满足筛选条件
  40. self.url_list.append(URL_PAGE(url,'get'))#添加到待取得url
  41. self.url_history.append(url)#添加到历史url
  42. self.__out_url(url)#输出历史url
  43. return True#写入成功
  44. return False#写入失败
  45. def del_url(self,index):#删除url
  46. self.__out_url_run(f'DELETE {self.url_list[index]}')
  47. del self.url_list[index]
  48. def get_url(self) -> URL_PAGE:#取得url
  49. url_page = self.url_list[0]
  50. self.__out_url_run(url_page.url)
  51. del self.url_list[0]
  52. return url_page
  53. def __out_url(self,url):#输出url历史
  54. self.file.write(f'{url}\n')
  55. self.file.flush()
  56. def __out_url_run(self,url):#输出已经运行的url
  57. self.file_run.write(f'{url}\n')
  58. self.file_run.flush()
  59. def return_url(self):
  60. return self.url_list.copy()
  61. def return_url_history(self):
  62. return self.url_history.copy()
  63. class Page_Downloader:
  64. num = 0
  65. def __init__(self,url:url,dic=''):
  66. self.url = url
  67. self.dir = dic
  68. Page_Downloader.num += 1
  69. self.page_source_dict = {}#页面保存信息
  70. self.cookie_Thread = None#子进程
  71. self.browser = None
  72. def __seeting(self,*args):#设置参数,请求头
  73. options = webdriver.ChromeOptions()
  74. options.add_argument('disable-infobars')# 不显示提示语句
  75. for i in args:
  76. if i == '':continue
  77. options.add_argument(i)
  78. return options
  79. def strat_urlGet(self,*args,func_cookie):#用get请求url ->得到一个页面信息
  80. self.break_ = False
  81. self.page_source_dict = {}
  82. self.nowurl = self.url.get_url()#获取一个url
  83. url = self.nowurl.url
  84. self.browser = webdriver.Chrome(chrome_options=self.__seeting(*args))
  85. self.browser.get(url)
  86. self.break_ = True
  87. def update_cookie():
  88. nonlocal self
  89. while self.break_:
  90. try:
  91. func_cookie(self.browser.get_cookies()) # 与GUI通信显示cookie
  92. time.sleep(.5)
  93. except:pass
  94. self.cookie_Thread = threading.Thread(target=update_cookie)
  95. self.cookie_Thread.start()
  96. self.Parser.browser = self.browser
  97. self.Parser.init(url)
  98. return self.browser
  99. def Del_cookies(self,name):#删除指定cookies
  100. browser = self.browser
  101. browser.delete_cookie(name)
  102. def Tra_cookies(self):#清空cookies
  103. browser = self.browser
  104. browser.delete_all_cookies()
  105. def Add_cookies(self,cookies:dict):#清空cookies
  106. browser = self.browser
  107. browser.add_cookie(cookies)
  108. def update_cookies(self,name,cookies:dict,):
  109. browser = self.browser
  110. cookies_list = browser.get_cookies()
  111. for i in cookies_list:
  112. if i.get('name',None) == name:
  113. browser.delete_cookie(name)#删除原来cookies
  114. i.update(cookies)
  115. browser.add_cookie(i)
  116. return
  117. raise Exception
  118. def set_Page_Parser(self,Parser):
  119. self.Parser = Parser
  120. self.Parser.browser = self.browser
  121. self.Parser.url = self.url
  122. self.Parser.dir = self.dir
  123. class Page_Parser:
  124. def __init__(self,Downloader:Page_Downloader):
  125. self.Downloader = Downloader
  126. self.Downloader.set_Page_Parser(self)
  127. self.func_list = []
  128. self.func_dict = {}
  129. self.init()
  130. def init(self,url=''):
  131. self.element_dict = {}#记录属性的名字
  132. self.now_url = url
  133. def add_base(self,func): # 装饰器
  134. def wrap(browser=None,num=None,name=None, *args, **kwargs) -> bool:
  135. try:
  136. func(browser=browser,num=num, name=name, *args, **kwargs)
  137. return True
  138. except:
  139. return False
  140. return wrap
  141. def add_func(self,name,func):
  142. n = len(self.func_list)
  143. self.func_list.append(f'{name}[{n}]')
  144. self.func_dict[f'{name}[{n}]'] = func
  145. def return_func(self):
  146. return self.func_list.copy()
  147. def find_ID(self,id,not_all=False,**kwargs):
  148. @self.add_base
  149. def find(browser, num, name, *args, **kwargs):
  150. nonlocal self,id
  151. if browser == None:browser = self.browser
  152. if not_all:self.element_dict[f'{name}[{num}]'] = [browser.find_element_by_id(id)]#返回必须是list
  153. else:self.element_dict[f'{name}[{num}]'] = browser.find_elements_by_id(id)
  154. self.add_func(f'find_ID:{id}',find)#添加func
  155. def find_class(self,class_name,not_all=False,**kwargs):
  156. @self.add_base
  157. def find(browser, num, name, *args, **kwargs):
  158. nonlocal self,class_name
  159. if browser == None:browser = self.browser
  160. if not_all:self.element_dict[f'{name}[{num}]'] = [browser.find_element_by_class_name(class_name)]#返回必须是list
  161. else:self.element_dict[f'{name}[{num}]'] = browser.find_elements_by_class_name(class_name)#返回必须是list
  162. self.add_func(f'find_class:{class_name}',find)#添加func
  163. def find_name(self,name_,not_all=False,**kwargs):
  164. @self.add_base
  165. def find(browser, num, name, *args, **kwargs):
  166. nonlocal self,name_
  167. if browser == None:browser = self.browser
  168. if not_all:self.element_dict[f'{name}[{num}]'] = [browser.find_element_by_name(name_)]#返回必须是list
  169. else:self.element_dict[f'{name}[{num}]'] = browser.find_elements_by_name(name_)#返回必须是list
  170. self.add_func(f'find_name:{name_}',find)#添加func
  171. def find_xpath(self,xpath,not_all=False,**kwargs):
  172. @self.add_base
  173. def find(browser, num, name, *args, **kwargs):
  174. nonlocal self,xpath
  175. if browser == None:browser = self.browser
  176. if not_all:self.element_dict[f'{name}[{num}]'] = [browser.find_element_by_xpath(xpath)]#返回必须是list
  177. else:self.element_dict[f'{name}[{num}]'] = browser.find_elements_by_xpath(xpath)#返回必须是list
  178. self.add_func(f'find_xpath:{xpath}',find)#添加func
  179. def find_css(self,css_selector,not_all=False,**kwargs):
  180. @self.add_base
  181. def find(browser, num, name, *args, **kwargs):
  182. nonlocal self,css_selector
  183. if browser == None:browser = self.browser
  184. if not_all:self.element_dict[f'{name}[{num}]'] = [browser.find_element_by_css_selector(css_selector)]#返回必须是list
  185. else:self.element_dict[f'{name}[{num}]'] = browser.find_elements_by_css_selector(css_selector)#返回必须是list
  186. self.add_func(f'find_css:{css_selector}',find)#添加func
  187. def find_tag_name(self,tag_name,not_all=False,**kwargs):
  188. @self.add_base
  189. def find(browser, num, name, *args, **kwargs):
  190. nonlocal self,tag_name
  191. if browser == None:browser = self.browser
  192. if not_all:self.element_dict[f'{name}[{num}]'] = [browser.find_element_by_tag_name(tag_name)]#返回必须是list
  193. else:self.element_dict[f'{name}[{num}]'] = browser.find_elements_by_tag_name(tag_name)#返回必须是list
  194. self.add_func(f'find_tagName:{tag_name}',find)#添加func\
  195. def find_link_text(self,link_text,not_all=False,**kwargs):#匹配link
  196. @self.add_base
  197. def find(browser, num, name, *args, **kwargs):
  198. nonlocal self,link_text
  199. if browser == None:browser = self.browser
  200. if not_all:self.element_dict[f'{name}[{num}]'] = [browser.find_element_by_link_text(link_text)]#返回必须是list
  201. else:self.element_dict[f'{name}[{num}]'] = browser.find_elements_by_link_text(link_text)#返回必须是list
  202. self.add_func(f'find_link_text:{link_text}',find)#添加func
  203. def find_partial_link_text(self,partial_link_text,not_all=False,**kwargs):#模糊匹配
  204. @self.add_base
  205. def find(browser, num, name, *args, **kwargs):
  206. nonlocal self,partial_link_text
  207. if browser == None:browser = self.browser
  208. if not_all:self.element_dict[f'{name}[{num}]'] = [browser.find_element_by_partial_link_text(partial_link_text)]#返回必须是list
  209. else:self.element_dict[f'{name}[{num}]'] = [browser.find_element_by_partial_link_text(partial_link_text)]#返回必须是list
  210. self.add_func(f'find_partial_link_text:{partial_link_text}',find)#添加func
  211. def find_switch_to_alert(self,*args,**kwargs):#定位弹出框
  212. @self.add_base
  213. def find(browser, num, name, *args, **kwargs):
  214. nonlocal self
  215. if browser == None:browser = self.browser
  216. self.element_dict[f'{name}[{num}]'] = [browser.switch_to.alert()]
  217. self.add_func(f'find_alert',find)#添加func
  218. def find_switch_to_active_element(self,*args,**kwargs):#定位焦点元素
  219. @self.add_base
  220. def find(browser, num, name, *args, **kwargs):
  221. nonlocal self
  222. if browser == None:browser = self.browser
  223. self.element_dict[f'{name}[{num}]'] = [browser.switch_to.active_element()]
  224. self.add_func(f'active_element',find)#添加func
  225. def find_switch_to_frame(self,reference,is_id=False,*args,**kwargs):#定位Frame
  226. @self.add_base
  227. def find(browser, num, name, *args, **kwargs):
  228. nonlocal self,reference,is_id
  229. if browser == None:browser = self.browser
  230. if reference == None:
  231. self.element_dict[f'{name}[{num}]'] = [browser.default_content()]# 回到主文档
  232. elif reference == '':
  233. self.element_dict[f'{name}[{num}]'] = [browser.parent_frame()]# 回到父文档
  234. else:
  235. if is_id:reference = int(reference)
  236. self.element_dict[f'{name}[{num}]'] = [browser.switch_to.frame(str(reference))]# 定位进入文档
  237. func_name = {None:'主文档','':'父文档'}.get(reference,reference)
  238. self.add_func(f'find_frame:{func_name}',find)#添加func
  239. def send_keys(self,text,element_value,index=0,**kwargs):#输入文字
  240. @self.add_base
  241. def action(*args, **kwargs):
  242. nonlocal self
  243. self.element_dict[element_value][index].send_keys(text)
  244. self.add_func(f'sent_text:{text}>{element_value}[{index}]', action) # 添加func
  245. def User_Passwd(self,User,Passwd,element_value,index=0,**kwargs):#输入验证(User&Password)
  246. @self.add_base
  247. def action(*args, **kwargs):
  248. nonlocal self
  249. self.element_dict[element_value][index].authenticate(User,Passwd)
  250. self.add_func(f'User:Passwd:{User};{Passwd}>{element_value}[{index}]', action) # 添加func
  251. def clear(self,element_value,index=0,**kwargs):#清空文本
  252. @self.add_base
  253. def action(*args, **kwargs):
  254. nonlocal self
  255. self.element_dict[element_value][index].clear()
  256. self.add_func(f'clear_text>{element_value}[{index}]', action) # 添加func
  257. def click(self,element_value,index=0,**kwargs):#点击按钮
  258. @self.add_base
  259. def action(*args, **kwargs):
  260. nonlocal self
  261. self.element_dict[element_value][index].click()
  262. self.add_func(f'click>{element_value}[{index}]', action) # 添加func
  263. def accept(self,element_value,index=0,**kwargs):#点击确定(弹出框)
  264. @self.add_base
  265. def action(*args, **kwargs):
  266. nonlocal self
  267. self.element_dict[element_value][index].accept()
  268. self.add_func(f'accept>{element_value}[{index}]', action) # 添加func
  269. def dismiss(self,element_value,index=0,**kwargs):#点击取消(弹出框)
  270. @self.add_base
  271. def action(*args, **kwargs):
  272. nonlocal self
  273. self.element_dict[element_value][index].dismiss()
  274. self.add_func(f'dismiss>{element_value}[{index}]', action) # 添加func
  275. def submit(self,element_value,index=0,**kwargs):#提交表单
  276. @self.add_base
  277. def action(*args, **kwargs):
  278. nonlocal self
  279. self.element_dict[element_value][index].submit()
  280. self.add_func(f'submit>{element_value}[{index}]', action) # 添加func
  281. def deselect_by_index(self,element_value,deselect,index=0,**kwargs):#根据index取消选择
  282. @self.add_base
  283. def action(*args, **kwargs):
  284. nonlocal self
  285. self.element_dict[element_value][index].deselect_by_index(int(deselect))
  286. self.add_func(f'deselect_by_index:{deselect}>{element_value}[{index}]', action) # 添加func
  287. def deselect_by_text(self,element_value,deselect,index=0,**kwargs):#根据text取消选择
  288. @self.add_base
  289. def action(*args, **kwargs):
  290. nonlocal self
  291. self.element_dict[element_value][index].deselect_by_visible_text(deselect)
  292. self.add_func(f'deselect_by_text:{deselect}>{element_value}[{index}]', action) # 添加func
  293. def deselect_by_value(self,element_value,deselect,index=0,**kwargs):#根据value取消选择
  294. @self.add_base
  295. def action(*args, **kwargs):
  296. nonlocal self
  297. self.element_dict[element_value][index].deselect_by_value(deselect)
  298. self.add_func(f'deselect_by_value:{deselect}>{element_value}[{index}]', action) # 添加func
  299. def select_by_index(self,element_value,deselect,index=0,**kwargs):#根据index选择
  300. @self.add_base
  301. def action(*args, **kwargs):
  302. nonlocal self
  303. self.element_dict[element_value][index].select_by_index(int(deselect))
  304. self.add_func(f'select_by_index:{deselect}>{element_value}[{index}]', action) # 添加func
  305. def select_by_text(self,element_value,deselect,index=0,**kwargs):#根据text选择
  306. @self.add_base
  307. def action(*args, **kwargs):
  308. nonlocal self
  309. self.element_dict[element_value][index].select_by_visible_text(deselect)
  310. self.add_func(f'select_by_text:{deselect}>{element_value}[{index}]', action) # 添加func
  311. def select_by_value(self,element_value,deselect,index=0,**kwargs):#根据value选择
  312. @self.add_base
  313. def action(*args, **kwargs):
  314. nonlocal self
  315. self.element_dict[element_value][index].select_by_value(deselect)
  316. self.add_func(f'select_by_value:{deselect}>{element_value}[{index}]', action) # 添加func
  317. def back(self,**kwargs):# 返回
  318. @self.add_base
  319. def action(*args, **kwargs):
  320. nonlocal self
  321. self.browser.back()
  322. self.add_func(f'BACK', action)
  323. def forward(self,**kwargs):# 前进
  324. @self.add_base
  325. def action(*args, **kwargs):
  326. nonlocal self
  327. self.browser.forward()
  328. self.add_func(f'FORWARD', action)
  329. def refresh(self,**kwargs):# 刷新
  330. @self.add_base
  331. def action(*args, **kwargs):
  332. nonlocal self
  333. self.browser.refresh()
  334. self.add_func(f'REFRESH', action)
  335. def wait_sleep(self,time:int=2,**kwargs):#暴力等待
  336. @self.add_base
  337. def action(*args, **kwargs):
  338. nonlocal self
  339. sleep(time)
  340. self.add_func(f'WAIT:{time}s', action)
  341. def set_wait(self,time:int=2,**kwargs):#隐式等待
  342. @self.add_base
  343. def action(*args, **kwargs):
  344. nonlocal self
  345. sleep(time)
  346. self.add_func(f'Loading_wait:{time}s', action)
  347. def run_JS(self,JS,**kwargs):
  348. @self.add_base
  349. def action(num,name,*args, **kwargs):
  350. nonlocal self
  351. get = self.browser.execute_script(JS)
  352. if hasattr(get,'__getitem__'):#可切片
  353. self.element_dict[f'{name}[{num}]'] = get # 返回必须是list
  354. else:
  355. self.element_dict[f'{name}[{num}]'] = [get]
  356. self.add_func(f'run_js:{JS}', action)
  357. def to_text(self,**kwargs):#获取网页源码
  358. @self.add_base
  359. def action(num,name,*args, **kwargs):
  360. nonlocal self
  361. self.element_dict[f'{name}[{num}]'] = [self.browser.page_source,self.now_url]
  362. self.add_func(f'get_page_source', action)
  363. def out_html(self,element_value,**kwargs):#输出网页源码
  364. @self.add_base
  365. def action(*args, **kwargs):
  366. nonlocal self
  367. md5 = hashlib.md5() # 应用MD5算法
  368. md5.update(f'{time.time()}_{self.now_url}'.encode('utf-8'))
  369. name = md5.hexdigest()
  370. save_dir = self.dir + '/' + name + '.html'
  371. print(save_dir)
  372. with open(save_dir,'w') as f:
  373. f.write(self.element_dict[element_value][0])
  374. with open(save_dir + '.CoTanURL','w') as f:
  375. f.write(self.element_dict[element_value][1])
  376. self.add_func(f'write_html<{element_value}', action)
  377. def del_all_cookies(self,**kwargs):#删除所有曲奇
  378. @self.add_base
  379. def action(*args, **kwargs):
  380. nonlocal self
  381. self.browser.delete_all_cookies()
  382. self.add_func(f'del_all_cookies', action)
  383. def del_cookies(self,cookies_name,**kwargs):#删除指定曲奇
  384. @self.add_base
  385. def action(*args, **kwargs):
  386. nonlocal self
  387. self.browser.delete_cookie(cookies_name)
  388. self.add_func(f'del_cookies:{cookies_name}', action)
  389. def add_cookies(self,cookies,**kwargs):#添加指定曲奇
  390. @self.add_base
  391. def action(*args, **kwargs):
  392. nonlocal self
  393. self.browser.add_cookie(cookies)
  394. self.add_func(f'add_cookies:{cookies}', action)
  395. def update_cookies(self,cookies_name,cookies,**kwargs):#更新曲奇
  396. @self.add_base
  397. def action(*args, **kwargs):
  398. nonlocal self
  399. now_cookies = self.browser.get_cookie(cookies_name)
  400. self.browser.delete_cookie(cookies_name)
  401. now_cookies.update(cookies)
  402. self.browser.add_cookie(now_cookies)
  403. self.add_func(f'add_cookies:{cookies}', action)
  404. def get_cookies(self,cookies_name,**kwargs):#获取指定曲奇
  405. @self.add_base
  406. def action(num,name,*args, **kwargs):
  407. nonlocal self
  408. self.element_dict[f'{name}[{num}]'] = [self.browser.get_cookie(cookies_name)]
  409. self.add_func(f'get_cookies:{cookies_name}', action)
  410. def get_all_cookies(self,**kwargs):#获取所有曲奇
  411. @self.add_base
  412. def action(num,name,*args, **kwargs):
  413. nonlocal self
  414. self.element_dict[f'{name}[{num}]'] = self.browser.get_cookie()
  415. self.add_func(f'get_all_cookies', action)
  416. def make_bs(self, element_value, **kwargs): # 解析成bs4对象
  417. @self.add_base
  418. def action(num,name,*args, **kwargs):
  419. nonlocal self
  420. self.element_dict[f'{name}[{num}]'] = [bs4.BeautifulSoup(self.element_dict[element_value][0], "html.parser")]
  421. self.add_func(f'Parsing:{element_value}', action) # 添加func
  422. #findAll需要修正为for循环
  423. def findAll(self, element_value,tag,attribute,limit,recursive):
  424. @self.add_base
  425. def action(num,name,*args, **kwargs):
  426. nonlocal self
  427. self.element_dict[f'{name}[{num}]'] = self.element_dict[element_value][0].findAll(tag,attribute,limit=limit,recursive=recursive)
  428. self.add_func(f'findAll:{element_value}', action) # 添加func
  429. def findAll_by_text(self, element_value,text,limit,recursive):
  430. @self.add_base
  431. def action(num,name,*args, **kwargs):
  432. nonlocal self
  433. self.element_dict[f'{name}[{num}]'] = self.element_dict[element_value][0].findAll(text=text,limit=limit,recursive=recursive)
  434. self.add_func(f'findAll_by_text:{element_value}', action) # 添加func
  435. def Element_interaction(self,update_func=lambda *args:None):#元素交互
  436. func_list = self.func_list
  437. status = None
  438. def update(func_name):
  439. nonlocal status,self
  440. if status:
  441. success_code = 'Success to run'
  442. elif status == None:
  443. success_code = 'No status'
  444. else:
  445. success_code = 'Wrong to run'
  446. value_box = []
  447. for i in self.element_dict:
  448. try:
  449. value_box.append(f'{i}[{len(i)}] = {self.element_dict[i]}')
  450. except:
  451. value_box.append(f'{i} = {self.element_dict[i]}')
  452. update_func(func_name, success_code, value_box) # 信息更新系统
  453. update('start')
  454. for func_num in range(len(func_list)):
  455. func_name = func_list[func_num]
  456. update(func_name)
  457. status = self.func_dict[func_name](num=f'{func_num}',name='var')
  458. update('Finish')