create_ad_layout.py 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712
  1. from selenium.webdriver.support.wait import WebDriverWait
  2. from selenium.webdriver.common.keys import Keys
  3. from selenium.webdriver import ActionChains
  4. from logging import handlers
  5. import logging
  6. import requests
  7. import random
  8. import shutil
  9. import time
  10. import re
  11. import os
  12. class CreateAd:
  13. def __init__(self, login_ad, service_name, wechat_name):
  14. self.log_ad = login_ad
  15. self.service_name = service_name
  16. self.wechat_name = wechat_name
  17. self.driver = login_ad.get_driver_loged()
  18. self.get_into_create_page()
  19. self.send_file_limit_num = 8
  20. self.img_dir = './img'
  21. def get_into_create_page(self):
  22. # 进入创建页面
  23. self.driver.find_element_by_id('material').click()
  24. WebDriverWait(self.driver, 10).until(lambda driver: driver.find_element_by_class_name('ui-fl-r'))
  25. create_element = self.driver.find_element_by_class_name('ui-fl-r')
  26. WebDriverWait(self.driver, 10).until(
  27. lambda driver: create_element.is_displayed() and create_element.is_enabled())
  28. # is_displayed 和 is_enabled 没有那么快就可以使用
  29. time.sleep(0.1)
  30. self.driver.find_element_by_class_name('ui-fl-r').click()
  31. WebDriverWait(self.driver, 5).until(lambda driver: driver.find_element_by_css_selector(
  32. '#wxadcontainer > div:nth-child(1) > div:nth-child(2) > div.dialog-1fj_N480ZT > div > div > div:nth-child(1) > div.dialogCardFooter-17KpBD1lgN > button'))
  33. self.driver.find_element_by_css_selector(
  34. '#wxadcontainer > div:nth-child(1) > div:nth-child(2) > div.dialog-1fj_N480ZT > div > div > div:nth-child(1) > div.dialogCardFooter-17KpBD1lgN > button').click()
  35. self.driver.switch_to.window(self.driver.window_handles[-1])
  36. WebDriverWait(self.driver, 100).until(lambda driver: driver.find_element_by_class_name('addContent-8pexaaAGYy'))
  37. self.driver.find_element_by_class_name('addContent-8pexaaAGYy').click()
  38. WebDriverWait(self.driver, 100).until(lambda driver: driver.find_element_by_class_name('topArea-qOwEAeNuIn'))
  39. def set_advertisement_sign(self, layout_name):
  40. # 设置广告标记
  41. self.driver.find_element_by_xpath('//*[@class="icon-edQB0KK2VG"]').click()
  42. input_element = self.driver.find_element_by_xpath('//input[@class="input-2lFnByGCRh"]')
  43. input_element.send_keys(Keys.BACKSPACE)
  44. input_element.send_keys(layout_name)
  45. def set_background_color(self, color):
  46. color_buttons = self.driver.find_elements_by_class_name('adui-cp-picker')
  47. c_buttons_can_use = []
  48. for _ in color_buttons:
  49. if _.is_displayed() and _.is_enabled():
  50. c_buttons_can_use.append(_)
  51. c_buttons_can_use[0].click()
  52. time.sleep(random.uniform(0.2, 0.3))
  53. input_elements = self.driver.find_elements_by_xpath('//input[@class="adui-input-base"]')
  54. for _ in input_elements:
  55. if _.is_enabled() and _.is_displayed() and _.get_attribute("value") == 'FFFFFF':
  56. _.click()
  57. _.send_keys(color)
  58. def set_head_assemb(self, info):
  59. def single_page_set():
  60. # TODO:选择图片之后,还有一些其他选项
  61. self.driver.find_element_by_xpath('//*[@id="stage-sidebar"]/div[1]/div/div[1]/div/div').click()
  62. time.sleep(random.uniform(0.1, 0.2))
  63. file_name = re.split('\/', info['content']['url'])[-1]
  64. self.driver.find_element_by_class_name('upload-img-item-inner-2gsg7NjaZ8').click()
  65. WebDriverWait(self.driver, 10).until(
  66. lambda x: len([_ for _ in self.driver.find_elements_by_class_name('title-29sncpKgTl') if
  67. _.is_displayed() and _.is_enabled()]) > 0)
  68. turn_page_buttons = self.driver.find_elements_by_class_name('paginationIcon-1EfoH0sNRF')
  69. can_use_button = []
  70. for _ in turn_page_buttons:
  71. if _.is_enabled() and _.is_displayed():
  72. can_use_button.append(_)
  73. # 不断翻页获取到元素为止
  74. chose_over = False
  75. while True:
  76. page_elements = self.driver.find_elements_by_class_name('title-29sncpKgTl')
  77. for _ in page_elements:
  78. if _.is_displayed() and _.is_enabled():
  79. if file_name in _.text:
  80. _.click()
  81. chose_over = True
  82. break
  83. if chose_over or len(can_use_button) == 0:
  84. break
  85. # 翻到最后一页时停止
  86. page_text = self.driver.find_element_by_class_name('count_small-37CcvfzoTl').text
  87. page_nums = re.findall('\d+', page_text)
  88. if int(page_nums[0].strip()) == int(page_nums[1].strip()):
  89. break
  90. # 翻页
  91. can_use_button[2].click()
  92. # 确保翻页成功
  93. WebDriverWait(self.driver, 10).until(
  94. lambda x: page_text != self.driver.find_element_by_class_name('count_small-37CcvfzoTl').text)
  95. self.driver.find_element_by_xpath('//*[@id="test_material_container_confirm"]').click()
  96. try:
  97. WebDriverWait(self.driver, 4).until(
  98. lambda driver: driver.find_element_by_class_name(
  99. 'btnFist-uueBS6DQFa'))
  100. _ = self.driver.find_element_by_class_name(
  101. 'btnFist-uueBS6DQFa')
  102. WebDriverWait(self.driver, 4).until(
  103. lambda x: (_.is_displayed() and _.is_enabled()))
  104. time.sleep(1)
  105. _.click()
  106. WebDriverWait(self.driver, 100).until(
  107. lambda driver: driver.find_element_by_class_name(
  108. 'btn-3E823IXt3m'))
  109. _ = self.driver.find_element_by_class_name(
  110. 'btn-3E823IXt3m')
  111. WebDriverWait(self.driver, 100).until(
  112. lambda x: (_.is_displayed() and _.is_enabled()))
  113. time.sleep(1)
  114. _.click()
  115. except Exception as e:
  116. pass
  117. logging.info('头版首页单图上传结束')
  118. def multi_page_set():
  119. # TODO:现在图片设置为素材库,需要对应下载然后存储
  120. self.driver.find_element_by_css_selector(
  121. '#stage-sidebar > div.topArea-qOwEAeNuIn > div > div:nth-child(2)').click()
  122. time.sleep(random.uniform(0.1, 0.2))
  123. page_size = len(info_v)
  124. if page_size == 3:
  125. pass
  126. if page_size == 4:
  127. self.driver.find_element_by_css_selector(
  128. '#stage-settings > div:nth-child(1) > div > div > div:nth-child(3) > div.adui-form-item > div.adui-form-control > div > button:nth-child(2)').click()
  129. if page_size == 6:
  130. self.driver.find_element_by_css_selector(
  131. '#stage-settings > div:nth-child(1) > div > div > div:nth-child(3) > div.adui-form-item > div.adui-form-control > div > button:nth-child(3)').click()
  132. time.sleep(random.uniform(0.1, 0.2))
  133. self.driver.find_element_by_class_name('imageUploadItem-tA9JX0RWua').click()
  134. WebDriverWait(self.driver, 1000).until(
  135. lambda driver: self.driver.find_element_by_class_name('adui-tabs-tab')
  136. )
  137. input_elements = self.driver.find_elements_by_tag_name('input')
  138. input_find_element = None
  139. for _ in input_elements:
  140. if '输入关键词搜索素材' in _.get_attribute('placeholder'):
  141. input_find_element = _
  142. for _ in info_v:
  143. file_name = os.path.basename(_)
  144. logging.info(file_name)
  145. input_find_element.send_keys(file_name)
  146. input_find_element.send_keys(Keys.RETURN)
  147. WebDriverWait(self.driver, 1000).until(
  148. lambda driver: driver.find_element_by_class_name('img-2HvhMmpnzP'))
  149. file_element = self.driver.find_element_by_class_name('img-2HvhMmpnzP')
  150. WebDriverWait(self.driver, 1000).until(
  151. lambda x: (file_element.is_displayed() and file_element.is_enabled()))
  152. ActionChains(self.driver).move_to_element(file_element).perform()
  153. time.sleep(random.uniform(0.5, 1))
  154. file_element.click()
  155. for i in range(len(file_name) + 10):
  156. input_find_element.send_keys(Keys.BACKSPACE)
  157. time.sleep(random.uniform(0.5, 1))
  158. self.driver.find_element_by_xpath('/html/body/div[12]/div/div/div[2]/div/div[3]/button[2]').click()
  159. # 切图操作如果有的话进行对应操作.
  160. for i in range(len(info_v) + 1):
  161. try:
  162. WebDriverWait(self.driver, 6).until(
  163. lambda driver: driver.find_element_by_xpath(
  164. '/html/body/div[13]/div/div/div[2]/div/div[3]/button[2]'))
  165. self.driver.find_element_by_xpath('/html/body/div[13]/div/div/div[2]/div/div[3]/button[2]').click()
  166. except:
  167. pass
  168. logging.info('头版多图选择 结束')
  169. def movie_set():
  170. # TODO:视频转为链接,
  171. file_name = os.path.basename(info_v)
  172. self.driver.find_element_by_xpath('//*[@id="stage-sidebar"]/div[1]/div/div[3]/div/div').click()
  173. self.driver.find_element_by_xpath('//*[@class="comptEditButton-2JsnAFdOGZ"]').click()
  174. WebDriverWait(self.driver, 100).until(
  175. lambda x: len([_ for _ in self.driver.find_elements_by_class_name('title-29sncpKgTl') if
  176. _.is_displayed() and _.is_enabled()]) > 0)
  177. #
  178. turn_page_buttons = self.driver.find_elements_by_class_name('paginationIcon-1EfoH0sNRF')
  179. can_use_button = []
  180. for _ in turn_page_buttons:
  181. if _.is_enabled() and _.is_displayed():
  182. can_use_button.append(_)
  183. # 不断翻页获取到元素为止
  184. chose_over = False
  185. while True:
  186. page_elements = self.driver.find_elements_by_class_name('title-29sncpKgTl')
  187. for _ in page_elements:
  188. if _.is_displayed() and _.is_enabled():
  189. if file_name in _.text:
  190. _.click()
  191. chose_over = True
  192. break
  193. if chose_over or len(can_use_button) == 0:
  194. # can_use_button 数量说明是否可以翻页,如果不可以翻页,则直接停止
  195. break
  196. # 翻到最后一页时停止
  197. page_text_elements = self.driver.find_elements_by_class_name('count_small-37CcvfzoTl')
  198. for _ in page_text_elements:
  199. if _.is_enabled() and _.is_displayed():
  200. page_text = _.text
  201. page_text_element = _
  202. page_nums = re.findall('\d+', page_text)
  203. if int(page_nums[0].strip()) == int(page_nums[1].strip()):
  204. break
  205. # 翻页
  206. can_use_button[2].click()
  207. # 确保翻页成功
  208. WebDriverWait(self.driver, 10).until(
  209. lambda x: page_text != page_text_element.text)
  210. sc_buttons = self.driver.find_elements_by_id('test_material_container_confirm')
  211. for _ in sc_buttons:
  212. if _.is_enabled() and _.is_displayed():
  213. _.click()
  214. info_type = info['type']
  215. info_v = None # TODO: 暂时存在,之后修改好multi_page_set 和movie_set.就删除
  216. if info['type'] == 'topImg':
  217. single_page_set()
  218. if info['type'] == 'topSlider':
  219. multi_page_set()
  220. if info['type'] == 'topVideo':
  221. movie_set()
  222. # 设置头部组件
  223. pass
  224. def set_page(self, page_link):
  225. # 设置图片模块
  226. self.driver.find_element_by_xpath('//*[@id="stage-sidebar"]/section/div[2]/div[1]/div/div').click()
  227. time.sleep(random.uniform(0.1, 0.2))
  228. file_name = re.split('\/', page_link)[-1]
  229. upload_elements = self.driver.find_elements_by_class_name('upload-img-item-inner-2gsg7NjaZ8')
  230. for _ in upload_elements:
  231. if _.is_displayed() and _.is_enabled():
  232. _.click()
  233. WebDriverWait(self.driver, 10).until(
  234. lambda x: len([_ for _ in self.driver.find_elements_by_class_name('title-29sncpKgTl') if
  235. _.is_displayed() and _.is_enabled()]) > 0)
  236. turn_page_buttons = self.driver.find_elements_by_class_name('paginationIcon-1EfoH0sNRF')
  237. can_use_button = []
  238. for _ in turn_page_buttons:
  239. if _.is_enabled() and _.is_displayed():
  240. can_use_button.append(_)
  241. # 不断翻页获取到元素为止
  242. chose_over = False
  243. while True:
  244. page_elements = self.driver.find_elements_by_class_name('title-29sncpKgTl')
  245. for _ in page_elements:
  246. if _.is_displayed() and _.is_enabled():
  247. if file_name in _.text:
  248. _.click()
  249. chose_over = True
  250. break
  251. if chose_over or len(can_use_button) == 0:
  252. # can_use_button 数量说明是否可以翻页,如果不可以翻页,则直接停止
  253. break
  254. # 翻到最后一页时停止
  255. page_text_elements = self.driver.find_elements_by_class_name('count_small-37CcvfzoTl')
  256. for _ in page_text_elements:
  257. if _.is_enabled() and _.is_displayed():
  258. page_text = _.text
  259. page_text_element = _
  260. page_nums = re.findall('\d+', page_text)
  261. if int(page_nums[0].strip()) == int(page_nums[1].strip()):
  262. break
  263. # 翻页
  264. can_use_button[2].click()
  265. # 确保翻页成功
  266. WebDriverWait(self.driver, 10).until(
  267. lambda x: page_text != page_text_element.text)
  268. sc_buttons = self.driver.find_elements_by_id('test_material_container_confirm')
  269. for _ in sc_buttons:
  270. if _.is_enabled() and _.is_displayed():
  271. _.click()
  272. try:
  273. WebDriverWait(self.driver, 4).until(
  274. lambda driver: driver.find_element_by_class_name(
  275. 'btnFist-uueBS6DQFa'))
  276. _ = self.driver.find_element_by_class_name(
  277. 'btnFist-uueBS6DQFa')
  278. WebDriverWait(self.driver, 4).until(
  279. lambda x: (_.is_displayed() and _.is_enabled()))
  280. # 已经出现但任需要等待
  281. time.sleep(1)
  282. _.click()
  283. WebDriverWait(self.driver, 100).until(
  284. lambda x: len([_ for _ in self.driver.find_elements_by_class_name('btn-3E823IXt3m') if
  285. _.is_displayed() and _.is_enabled()]) > 0)
  286. for _ in self.driver.find_elements_by_class_name('btn-3E823IXt3m'):
  287. if _.is_displayed() and _.is_enabled():
  288. _.click()
  289. except Exception as e:
  290. logging.info(e)
  291. logging.info('图片模块设置结束')
  292. def set_content(self, config_info):
  293. # TODO:长文本需要优化输入时间
  294. logging.info(' 开始设置文本模块')
  295. # 设置文本模块
  296. # 1.文本内容2.文本颜色3.是否加粗4.文本位置设置5.文本大小
  297. # 设置文本内容
  298. self.driver.find_element_by_xpath('//*[@id="stage-sidebar"]/section/div[2]/div[5]/div/div').click()
  299. time.sleep(random.uniform(0.2, 0.3))
  300. input_elements = self.driver.find_elements_by_xpath('//textarea[@class="adui-input-base"]')
  301. for _ in input_elements:
  302. if _.is_enabled() and _.is_displayed():
  303. _.send_keys(config_info['text'])
  304. # 设置颜色
  305. if config_info['color'] != '595959':
  306. color_buttons = self.driver.find_elements_by_class_name('adui-cp-picker')
  307. c_buttons_can_use = []
  308. for _ in color_buttons:
  309. if _.is_displayed() and _.is_enabled():
  310. c_buttons_can_use.append(_)
  311. c_buttons_can_use[1].click()
  312. time.sleep(random.uniform(0.2, 0.3))
  313. input_elements = self.driver.find_elements_by_tag_name('input')
  314. for _ in input_elements:
  315. if _.is_enabled() and _.is_displayed() and _.get_attribute("value") == '595959':
  316. _.click()
  317. _.send_keys(config_info['color'])
  318. # 设置是否加粗
  319. if config_info['fontWeight'] != 'normal':
  320. # TODO:新格式 文本是否加粗,还不知道
  321. big_elements = self.driver.find_elements_by_class_name('adui-button-content')
  322. for _ in big_elements:
  323. if _.text == '加粗' and _.is_displayed() and _.is_enabled():
  324. _.click()
  325. # 设置文本位置
  326. if config_info['textAlign'] != 'left':
  327. # TODO:新格式 文本位置设置,还不知道
  328. loc_buttons = self.driver.find_elements_by_xpath(
  329. "//div[contains(@class, 'adui-button-group_banner')]//button")
  330. loc_buttons_can_use = []
  331. for _ in loc_buttons:
  332. if _.is_enabled() and _.is_displayed():
  333. loc_buttons_can_use.append(_)
  334. if config_info['textAlign'] == 'center':
  335. loc_buttons_can_use[1].click()
  336. if config_info['textAlign'] == 'right':
  337. loc_buttons_can_use[2].click()
  338. # 设置文本大小
  339. if config_info['fontSize'] != 15:
  340. str_buttons = self.driver.find_elements_by_xpath("//*[@class='adui-select-selection-search']")
  341. str_buttons_can_use = []
  342. for _ in str_buttons:
  343. if _.is_displayed() and _.is_enabled():
  344. str_buttons_can_use.append(_)
  345. str_buttons_can_use[1].click()
  346. time.sleep(random.uniform(0.5, 1))
  347. str_num_buttons = self.driver.find_elements_by_xpath("//*[@class='adui-select-item-option-content']")
  348. str_num_can_use = []
  349. for _ in str_num_buttons:
  350. if _.is_displayed() and _.is_enabled():
  351. str_num_can_use.append(_)
  352. str_num_map = {14: 0, 16: 1, 18: 2, 20: 3, 24: 4, 36: 5}
  353. str_num_can_use[str_num_map[config_info['fontSize']]].click()
  354. # 设置文本边距
  355. if config_info['marginTop'] != 22 or config_info['marginBottom'] != 22:
  356. distance_buttons = self.driver.find_elements_by_xpath('//input[@class="adui-input-base"]')
  357. distance_buttons_can_use = []
  358. for _ in distance_buttons:
  359. if _.is_enabled() and _.is_displayed() and _.get_attribute("value") == '22':
  360. distance_buttons_can_use.append(_)
  361. distance_buttons_can_use[0].click()
  362. for i in range(4):
  363. distance_buttons_can_use[0].send_keys(Keys.BACKSPACE)
  364. distance_buttons_can_use[0].send_keys(config_info['marginTop'])
  365. distance_buttons_can_use[1].click()
  366. for i in range(4):
  367. distance_buttons_can_use[1].send_keys(Keys.BACKSPACE)
  368. distance_buttons_can_use[1].send_keys(config_info['marginBottom'])
  369. def set_follow_button(self, config_info):
  370. # TODO:是否一键关注
  371. # 设置关注按钮
  372. # 1.设置button文本内容 2.是否加粗 3.设置字体颜色,边框颜色,填充色 4.设置边距
  373. self.driver.find_element_by_xpath('//*[@id="stage-sidebar"]/section/div[4]/div[2]/div/div').click()
  374. # 文本设置
  375. input_elements = self.driver.find_elements_by_xpath('//input[@class="adui-input-base"]')
  376. for _ in input_elements:
  377. if _.is_enabled() and _.is_displayed() and _.get_attribute("value") == '关注公众号':
  378. _.click()
  379. _.clear()
  380. for i in range(10):
  381. _.send_keys(Keys.BACKSPACE)
  382. _.send_keys(config_info['text'])
  383. # 文本是否加粗
  384. if config_info['fontWeight'] != 'normal':
  385. big_elements = self.driver.find_elements_by_xpath('//span[@class="adui-button-content"]')
  386. for _ in big_elements:
  387. if _.text == '加粗' and _.is_displayed() and _.is_enabled():
  388. _.click()
  389. # 颜色设置
  390. input_elements = self.driver.find_elements_by_xpath('//input[@class="adui-input-base"]')
  391. input_elements_can_use = []
  392. for _ in input_elements:
  393. if _.is_enabled() and _.is_displayed() and (
  394. _.get_attribute("value") == '07C160' or _.get_attribute("value") == 'FFFFFF'):
  395. input_elements_can_use.append(_)
  396. if config_info['borderColor'] != '#FFFFFF':
  397. input_elements_can_use[0].click()
  398. input_elements_can_use[0].send_keys(config_info['textColor'])
  399. time.sleep(random.uniform(0.1, 0.5))
  400. if config_info['borderColor'] != '#FFFFFF':
  401. input_elements_can_use[1].click()
  402. input_elements_can_use[1].send_keys(config_info['borderColor'])
  403. time.sleep(random.uniform(0.1, 0.5))
  404. input_elements_can_use[2].click()
  405. input_elements_can_use[2].send_keys(config_info['backColor'])
  406. time.sleep(random.uniform(0.1, 0.5))
  407. # 间隙设置
  408. size_buttons = self.driver.find_elements_by_xpath('//input[@class="adui-input-base"]')
  409. size_buttons_can_use = []
  410. for _ in size_buttons:
  411. if _.is_enabled() and _.is_displayed() and _.get_attribute("value") == '28':
  412. size_buttons_can_use.append(_)
  413. size_buttons_can_use[0].click()
  414. for i in range(4):
  415. size_buttons_can_use[0].send_keys(Keys.BACKSPACE)
  416. size_buttons_can_use[0].send_keys(config_info['marginTop'])
  417. size_buttons_can_use[1].click()
  418. for i in range(4):
  419. size_buttons_can_use[1].send_keys(Keys.BACKSPACE)
  420. size_buttons_can_use[1].send_keys(config_info['marginBottom'])
  421. def set_text_button(self):
  422. # 设置图文按钮
  423. pass
  424. def send_file_multi(self, layout, err_num=0):
  425. # 有问题,暂时不使用
  426. # 上传文件,文件上传与整体流程切割开
  427. token = re.findall('token=(\d+)', self.driver.current_url)
  428. url_ = 'https://mp.weixin.qq.com/promotion/frame?t=ad_system/common_frame&t1=material_std/material_library&token={}'.format(
  429. token[0])
  430. js = "window.open('{}')".format(url_)
  431. self.driver.execute_script(js)
  432. time.sleep(random.uniform(1, 2))
  433. self.driver.switch_to.window(self.driver.window_handles[-1])
  434. file_set = set()
  435. for v in layout.values():
  436. if isinstance(v, dict):
  437. if 'multi_page' in v.keys() or 'page' in v.keys() or 'movie' in v.keys():
  438. v_name = list(v.keys())[0]
  439. if isinstance(v[v_name], list):
  440. for _ in v[v_name]:
  441. file_set.add(_)
  442. else:
  443. file_set.add(v[v_name])
  444. file_list = list(file_set)
  445. # print(file_list)
  446. # print('file list size', len(file_list))
  447. send_file_sign = self.send_file_limit_num
  448. for _ in file_list:
  449. # print(_)
  450. self.driver.find_element_by_xpath('//*[@id="wxadcontainer"]/div[1]/div[2]/div[4]/input').send_keys(_)
  451. time.sleep(100)
  452. while True:
  453. # 失败,失败直接退出重跑
  454. # 正在上传数量,如果是正在上传小于限定数量,就不断输入
  455. # 上传完毕,小于限定数量,不断输入,.....已经上传好了,就关闭
  456. time.sleep(1)
  457. send_reslut_content = self.driver.find_element_by_xpath(
  458. '//*[@id="wxadcontainer"]/div[1]/div[2]/div[4]/div/strong').text
  459. if '失败' in send_reslut_content:
  460. if err_num < 3:
  461. self.send_file(layout, err_num=err_num + 1)
  462. else:
  463. exit()
  464. if '正在上传' in send_reslut_content:
  465. if send_file_sign < len(file_list):
  466. send_num = re.findall('(\d+)', send_reslut_content)[0]
  467. if int(send_num) < self.send_file_limit_num:
  468. # 还可以继续上传
  469. x = send_file_sign
  470. can_send_sign = send_file_sign + (self.send_file_limit_num - send_num)
  471. y = can_send_sign if can_send_sign < len(file_list) else len(file_list)
  472. for i in range(x, y):
  473. send_file_sign = send_file_sign + 1
  474. self.driver.find_element_by_xpath(
  475. '//*[@id="wxadcontainer"]/div[1]/div[2]/div[4]/input').send_keys(file_list[i])
  476. else:
  477. pass
  478. if '上传成功' in send_reslut_content:
  479. if send_file_sign < len(file_list):
  480. send_num = re.findall('(\d+)', send_reslut_content)[0]
  481. if int(send_num) < self.send_file_limit_num:
  482. # 还可以继续上传
  483. x = send_file_sign
  484. can_send_sign = send_file_sign + (self.send_file_limit_num - send_num)
  485. y = can_send_sign if can_send_sign < len(file_list) else len(file_list)
  486. for i in range(x, y):
  487. send_file_sign = send_file_sign + 1
  488. self.driver.find_element_by_xpath(
  489. '//*[@id="wxadcontainer"]/div[1]/div[2]/div[4]/input').send_keys(file_list[i])
  490. else:
  491. break
  492. time.sleep(1000)
  493. self.driver.execute_script('window.close();')
  494. def send_file(self, file_link, err_num=0):
  495. # 下载图片,存储于
  496. if not os.path.exists(self.img_dir):
  497. os.makedirs(self.img_dir)
  498. link_pra = re.split('\/', file_link)
  499. file_path = os.getcwd() + '/' + self.img_dir + '/' + link_pra[-1]
  500. rsp = requests.get(file_link)
  501. with open(file_path, 'wb') as f:
  502. f.write(rsp.content)
  503. # 有问题,暂时不使用
  504. self.driver.execute_script('location.reload();')
  505. self.driver.find_element_by_xpath('//*[@id="wxadcontainer"]/div[1]/div[2]/div[4]/input').send_keys(file_path)
  506. def send_file_alone(self, layout):
  507. def get_url(v_info):
  508. if 'url' in v_info.keys():
  509. file_set.add(v_info['url'])
  510. for v in v_info.values():
  511. if isinstance(v, dict):
  512. get_url(v)
  513. if isinstance(v, list):
  514. for _ in v:
  515. if isinstance(_, dict):
  516. get_url(_)
  517. # 上传文件,单线程
  518. # 上传文件,文件上传与整体流程切割开
  519. WebDriverWait(self.driver, 10).until(
  520. lambda x: len(re.findall('token=(\d+)', self.driver.current_url)))
  521. token = re.findall('token=(\d+)', self.driver.current_url)
  522. url_ = 'https://mp.weixin.qq.com/promotion/frame?t=ad_system/common_frame&t1=material_std/material_library&token={}'.format(
  523. token[0])
  524. js = "window.open('{}')".format(url_)
  525. self.driver.execute_script(js)
  526. time.sleep(random.uniform(1, 2))
  527. self.driver.switch_to.window(self.driver.window_handles[-1])
  528. file_set = set()
  529. # TODO:之后还有multi_page 和 movie
  530. # for v in layout.values():
  531. # if isinstance(v, dict):
  532. # if 'multi_page' in v.keys() or 'page' in v.keys() or 'movie' in v.keys():
  533. # v_name = list(v.keys())[0]
  534. # if isinstance(v[v_name], list):
  535. # for _ in v[v_name]:
  536. # file_set.add(_)
  537. # else:
  538. # file_set.add(v[v_name])
  539. get_url(layout)
  540. for _ in file_set:
  541. self.send_file(_)
  542. err_num = 0
  543. while True:
  544. time.sleep(1)
  545. send_reslut_content = self.driver.find_element_by_xpath(
  546. '//*[@id="wxadcontainer"]/div[1]/div[2]/div[4]/div/strong').text
  547. if '上传成功' in send_reslut_content:
  548. break
  549. if '失败' in send_reslut_content:
  550. err_num = err_num + 1
  551. self.send_file(_)
  552. if err_num > 3:
  553. raise ValueError("图片上传失败")
  554. self.driver.execute_script('window.close();')
  555. self.driver.switch_to.window(self.driver.window_handles[-1])
  556. def set_share_content(self, title_content, des_content):
  557. self.driver.find_element_by_xpath('//*[@id="wxadcontainer"]/div[1]/div/section/header/div[2]/button[2]').click()
  558. WebDriverWait(self.driver, 50).until(lambda driver: driver.find_element_by_xpath(
  559. '//*[@id="wxadcontainer"]/div[1]/div/div/div/div[1]/section/section/div[2]/div[1]/div/div/input'))
  560. title_input = self.driver.find_element_by_xpath(
  561. '//*[@id="wxadcontainer"]/div[1]/div/div/div/div[1]/section/section/div[2]/div[1]/div/div/input')
  562. title_input.click()
  563. title_input.send_keys(title_content)
  564. des_input = self.driver.find_element_by_xpath(
  565. '//*[@id="wxadcontainer"]/div[1]/div/div/div/div[1]/section/section/div[2]/div[2]/div/div/input')
  566. des_input.click()
  567. des_input.send_keys(des_content)
  568. self.driver.find_element_by_xpath('//*[@id="wxadcontainer"]/div[1]/div/header/div[2]/button').click()
  569. WebDriverWait(self.driver, 10).until(
  570. lambda driver: driver.find_element_by_xpath('/html/body/div[6]/div/div/div[2]/div/div[3]/button[2]'))
  571. self.driver.find_element_by_xpath('/html/body/div[6]/div/div/div[2]/div/div[3]/button[2]').click()
  572. time.sleep(1)
  573. @staticmethod
  574. def check_sucess_api(log_ad, layout_name):
  575. # 默认在进入公众号初始页面
  576. logging.info('开始检查落地页是否创建成功')
  577. WebDriverWait(log_ad.driver, 100).until(
  578. lambda driver: True if 'token' in log_ad.driver.current_url else False)
  579. cookie_dict = log_ad.get_cookie(log_ad.driver, login_cookie=False)
  580. token_id = re.findall('token=(\d+)', log_ad.driver.current_url)[0]
  581. requests.session()
  582. layout_url = 'https://mp.weixin.qq.com/promotion/landingpage_manager?action=list_pages&page=1&page_size=10&canvas_name={layout_name}&login_from=&is_grant=0&owner_uid=&token={wechat_token}&appid=&spid=&_={time_}'.format(
  583. layout_name=layout_name, wechat_token=token_id, time_=int(time.time() * 1000))
  584. session = requests.session()
  585. rsp = session.get(url=layout_url, cookies=cookie_dict)
  586. result_json = rsp.json()
  587. if 'landing_page_list' in result_json.keys():
  588. if len(result_json['landing_page_list']):
  589. logging.info('对应落地页存在于微信后台')
  590. return True
  591. def remove_all_file(self):
  592. shutil.rmtree(os.getcwd() + '/' + self.img_dir)
  593. pass
  594. def create_layout(self, layout, err_num=0):
  595. #
  596. try:
  597. self.send_file_alone(layout)
  598. self.set_advertisement_sign(layout_name=layout['layoutName'])
  599. self.set_head_assemb(layout['topContent'])
  600. self.set_background_color(layout['pageBackColor'])
  601. for _ in layout['content']:
  602. if _['type'] == 'img':
  603. self.set_page(page_link=_['content']['url'])
  604. if _['type'] == 'txt':
  605. self.set_content(_['content'])
  606. if _['type'] == 'followAcc':
  607. self.set_follow_button(_['content'])
  608. self.set_share_content(title_content=layout['shareTittle'], des_content=layout['shareDesc'])
  609. self.remove_all_file()
  610. if self.check_sucess_api(layout_name=layout['layoutName'], log_ad=self.log_ad):
  611. return {'sucess': True, 'result_info': ''}
  612. else:
  613. if err_num > 3:
  614. return {'sucess': False, 'result_info': '过程中全程无错误,失败'}
  615. else:
  616. self.log_ad.refresh_driver()
  617. self.log_ad.select_ad_master(service_name=self.service_name, wechat_name=self.wechat_name)
  618. self.get_into_create_page()
  619. return self.create_layout(layout, err_num=err_num + 1)
  620. except Exception as e:
  621. raise
  622. logging.error(e)
  623. # TODO:有空时讲 e 内容设置为原始内容
  624. if err_num > 3:
  625. return {'sucess': False, 'result_info': str(e)}
  626. else:
  627. self.log_ad.refresh_driver()
  628. self.log_ad.select_ad_master(service_name=self.service_name, wechat_name=self.wechat_name)
  629. self.get_into_create_page()
  630. return self.create_layout(layout, err_num=err_num + 1)
  631. if __name__ == '__main__':
  632. logging.basicConfig(
  633. handlers=[
  634. logging.handlers.RotatingFileHandler('./create_ad_layout.log',
  635. maxBytes=10 * 1024 * 1024,
  636. backupCount=5,
  637. encoding='utf-8')
  638. , logging.StreamHandler() # 供输出使用
  639. ],
  640. level=logging.INFO,
  641. format="%(asctime)s - %(levelname)s %(filename)s %(funcName)s %(lineno)s - %(message)s"
  642. )