create_ad_layout.py 36 KB

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