fb_web_bot.py 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571
  1. # coding: utf-8
  2. from selenium import webdriver
  3. from selenium.common.exceptions import NoSuchElementException
  4. from selenium.webdriver.common.keys import Keys
  5. from selenium.webdriver import ChromeOptions
  6. from datetime import datetime as dt
  7. from time import sleep
  8. import time
  9. import os
  10. import json
  11. import re
  12. import operator
  13. CREDS = {'user': 'deeejas@yandex.com', 'pass': 'TB1984_li'}
  14. selfProfile = "https://mbasic.facebook.com/profile.php?fref=pb"
  15. self_name = 'Levente Marton'
  16. def count_down(t, d_type, up_down, max_count=None):
  17. if up_down == 'down':
  18. _one = -1
  19. _OPERAND = operator.ge
  20. max_count = 0
  21. finish = 'count%s finished' % up_down
  22. elif up_down == 'up':
  23. _one = 1
  24. _OPERAND = operator.le
  25. finish = 'count%s finished' % up_down
  26. max_count = max_count
  27. while _OPERAND(t, max_count):
  28. if d_type == 'm':
  29. mins, secs = divmod(t, 60)
  30. tf = '{0:2d}:{1:2d}'.format(mins, secs)
  31. print(tf, end='\r')
  32. time.sleep(1)
  33. t += _one
  34. elif d_type == 'h':
  35. hour, rem = divmod(t, 60)
  36. _, secs = divmod(rem, 60)
  37. hours, mins = divmod(hour, 60)
  38. tf = '{0:02d}:{1:02d}:{2:02d}'.format(hours, mins, secs)
  39. print(tf, end='\r')
  40. time.sleep(1)
  41. t += _one
  42. else:
  43. print(finish)
  44. def mfacebookToBasic(url):
  45. '''Reformat a url to load mbasic facebook instead of regular facebook, return the same string if
  46. the url don't contains facebook'''
  47. if "m.facebook.com" in url:
  48. return url.replace("m.facebook.com", "mbasic.facebook.com")
  49. elif "www.facebook.com" in url:
  50. return url.replace("www.facebook.com", "mbasic.facebook.com")
  51. else:
  52. return url
  53. class Person():
  54. '''Basic class for people's profiles'''
  55. def __init__(self):
  56. self.name = ""
  57. self.profileLink = ""
  58. self.addLink = ""
  59. def __str__(self):
  60. s = ""
  61. s += self.name + ":\n"
  62. s += "Profile Link: " + self.profileLink
  63. if self.addLink != "":
  64. s += "Addlink ->: " + self.addLink
  65. return s
  66. def __repr__(self):
  67. self.__str__()
  68. class Post():
  69. '''Class to contain information about a post'''
  70. def __init__(self):
  71. self.posterName = ""
  72. self.text = ""
  73. self.numLikes = 0
  74. self.time = ""
  75. self.privacy = ""
  76. self.posterLink = ""
  77. self.linkToComment = ""
  78. self.linkToLike = ""
  79. self.linkToLikers = ""
  80. self.linkToReport = ""
  81. self.groupLink = ""
  82. self.linkToShare = ""
  83. self.linkToMore = ""
  84. self.numComents = 0
  85. def toDict(self):
  86. return self.__dict__.copy()
  87. def fromDict(self, d):
  88. self.__dict__ = d.copy()
  89. def from_json(self, j):
  90. self.fromDict(json.loads(j))
  91. def from_json_file(self, f):
  92. self.fromDict(json.loads(open(f, "rt").read()))
  93. def to_json(self):
  94. return json.dumps(self.toDict())
  95. def __str__(self):
  96. s = "\nPost by " + self.posterName + ": "
  97. s += self.text + "\n"
  98. s += "Likes: " + str(self.numLikes) + " - "
  99. s += "Comments: " + str(self.numComents) + " - "
  100. s += self.time + " "
  101. s += " - Privacy: " + self.privacy + "\n-"
  102. s += "\n Comment -> " + self.linkToComment + "\n"
  103. return s
  104. def __repr__(self):
  105. return self.__str__()
  106. class FacebookBot(webdriver.Chrome):
  107. '''Main class for browsing facebook'''
  108. def __init__(self, executable_path='chromedriver', visible=False):
  109. '''relativePhatomJs = "\\phantomjs.exe"
  110. service_args = None
  111. if images == False:
  112. service_args = ['--load-images=no', ]
  113. if pathToPhantomJs == None:
  114. path = self, os.getcwd() + relativePhatomJs
  115. else:
  116. path = pathToPhantomJs
  117. webdriver.PhantomJS.__init__(self, path, service_args=service_args)
  118. '''
  119. self.visible = visible
  120. self.executable_path = executable_path
  121. self.chrome_options = ChromeOptions()
  122. self.chrome_options.add_argument('--disable-infobars')
  123. self.chrome_options.add_argument('--no-sandbox')
  124. self.chrome_options.add_argument('--disable-dev-shm-usage')
  125. self.chrome_options.add_argument('--disable-gpu')
  126. if self.visible is False:
  127. self.chrome_options.add_argument('--headless')
  128. webdriver.Chrome.__init__(self, executable_path=self.executable_path, options=self.chrome_options)
  129. def get(self, url):
  130. '''The make the driver go to the url but reformat the url if is for facebook page'''
  131. super().get(mfacebookToBasic(url))
  132. def login(self, email, password):
  133. '''Log to facebook using email (str) and password (str)'''
  134. url = "https://mbasic.facebook.com"
  135. self.get(url)
  136. email_element = self.find_element_by_name("email")
  137. email_element.send_keys(email)
  138. pass_element = self.find_element_by_name("pass")
  139. pass_element.send_keys(password)
  140. pass_element.send_keys(Keys.ENTER)
  141. try:
  142. confirm_element = self.find_element_by_xpath('//*[@id="root"]/table/tbody/tr/td/div/form/div/input')
  143. confirm_element.click()
  144. except NoSuchElementException:
  145. print('No confirm element found')
  146. try:
  147. self.find_element_by_name("xc_message")
  148. print("Logged in")
  149. return True
  150. except NoSuchElementException as dummy:
  151. print("Fail to login")
  152. return False
  153. def logout(self):
  154. '''Log out from Facebook'''
  155. url = "https://mbasic.facebook.com/logout.php?h=AffSEUYT5RsM6bkY&t=1446949608&ref_component=mbasic_footer&ref_page=%2Fwap%2Fhome.php&refid=7"
  156. try:
  157. self.get(url)
  158. print('logged out')
  159. return True
  160. except Exception as e:
  161. print("Failed to log out ->\n", e)
  162. return False
  163. def postTextToURL(self, text, url):
  164. '''Post text(str) to url (str), url can be a group, fan page or profile'''
  165. try:
  166. self.get(url)
  167. textbox = self.find_element_by_name("xc_message")
  168. textbox.send_keys(text)
  169. submit = self.find_element_by_name("view_post")
  170. submit.click()
  171. return True
  172. except Exception as e:
  173. print("Failed to post in ", url, "->\n", e)
  174. return False
  175. def postTextToTimeline(self, text):
  176. '''Shortcut to post in your own timeline'''
  177. url = "https://mbasic.facebook.com/"
  178. return self.postTextToURL(text, url)
  179. def newMessageToFriend(
  180. self,
  181. friendname,
  182. message,
  183. image1=None,
  184. image2=None,
  185. image3=None):
  186. '''Send message(str) to friend name (str), images doesn work in phantomjs'''
  187. url = "https://mbasic.facebook.com/friends/selector/?return_uri=%2Fmessages%2Fcompose%2F&cancel_uri=https%3A%2F%2Fm.facebook.com%2Fmessages%2F&friends_key=ids&context=select_friend_timeline&refid=11"
  188. self.get(url)
  189. q = self.find_element_by_name("query")
  190. q.send_keys(friendname)
  191. q.send_keys(Keys.ENTER)
  192. id = self.page_source.split(
  193. "/messages/compose/?ids=")[1].split('"><span>')[0].split('"><span>')[0]
  194. url = "https://mbasic.facebook.com/messages/compose/?ids=" + id
  195. self.get(url)
  196. t = self.find_element_by_name("body")
  197. t.send_keys(message)
  198. t.send_keys(Keys.ENTER)
  199. f1 = self.find_element_by_name("file1")
  200. f2 = self.find_element_by_name("file2")
  201. f3 = self.find_element_by_name("file3")
  202. if image1 is not None:
  203. f1.send_keys(image1)
  204. if image2 is not None:
  205. f2.send_keys(image2)
  206. if image3 is not None:
  207. f3.send_keys(image3)
  208. send = self.find_element_by_name("Send")
  209. send.send_keys(Keys.ENTER)
  210. return True
  211. def getPostInGroup(self, url, deep=2, moreText="no more posts"):
  212. '''Get a list of posts (list:Post) in group url(str) iterating deep(int) times in the group
  213. pass moreText depending of your language, i couldn't find a elegant solution for this'''
  214. self.get(url)
  215. ids = [4, 5, 6, 7, 8, 9, 'a', 'b', 'c', 'd', 'e', 'f']
  216. posts = []
  217. for n in range(deep):
  218. # print("Searching, deep ",n)
  219. for i in ids:
  220. # print(i)
  221. post = Post()
  222. try:
  223. p = self.find_element_by_id("u_0_" + str(i))
  224. # print(p.get_attribute('id'))
  225. # print(p.text)
  226. a = p.find_elements_by_tag_name("a")
  227. post.posterName = a[0].text
  228. try:
  229. post.numLikes = int(a[4].text.split(" ")[0])
  230. # post.numLikes = int(a[2].text.split(" ")[0])
  231. except ValueError:
  232. post.numLikes = 0
  233. post.text = p.find_element_by_tag_name("p").text
  234. post.time = p.find_element_by_tag_name("abbr").text
  235. # p.text.split("· ")[1].split("\n")[0]
  236. post.privacy = self.title
  237. post.posterLink = a[0].get_attribute('href')
  238. # p.find_element_by_class_name("du").get_attribute('href')
  239. # post.linkToComment = a[4].get_attribute('href')
  240. post.linkToComment = a[2].get_attribute('href')
  241. # post.linkToLike = a[2].get_attribute('href')
  242. post.linkToLike = a[4].get_attribute('href')
  243. try:
  244. post.numComents = int(a[4].text.split(" ")[0])
  245. # post.numComents = int(a[5].text.split(" ")[0])
  246. except ValueError:
  247. post.numComents = 0
  248. # post.linkToShare = a[5].get_attribute('href')
  249. post.linkToLikers = a[1].get_attribute('href')
  250. # post.linkToMore = a[6].get_attribute('href')
  251. if post not in posts:
  252. posts.append(post)
  253. except Exception as dummy:
  254. # print(str(exc))
  255. # print(exc.args)
  256. # print(exc)
  257. continue
  258. try:
  259. more = self.find_element_by_partial_link_text(
  260. moreText).get_attribute('href')
  261. self.get(more)
  262. # self.find_element_by_partial_link_text(moreText)
  263. except Exception as dummy:
  264. # print(e)
  265. print("no more posts")
  266. return posts
  267. def postInGroup(self, groupURL, text):
  268. '''Post text(str) in a group'''
  269. self.get(groupURL)
  270. try:
  271. tf = self.find_element_by_name("xc_message")
  272. except NoSuchElementException:
  273. print(" Group url doesn't exist or you don't have permissions to see it")
  274. return False
  275. tf.send_keys(text)
  276. self.find_element_by_name("view_post").send_keys(Keys.ENTER)
  277. print('new post created')
  278. return True
  279. def postImageInGroup(self, url, text, image1, image2="", image3=""):
  280. '''Post image(str) in a group(url:str) with the text(str), doesn't work in phantomJS'''
  281. self.get(url)
  282. v = self.find_element_by_name("view_photo")
  283. v.send_keys(Keys.ENTER)
  284. self.save_screenshot("debug.jpg")
  285. i1 = self.find_element_by_name("file1")
  286. i2 = self.find_element_by_name("file2")
  287. i3 = self.find_element_by_name("file3")
  288. i1.send_keys(image1)
  289. i2.send_keys(image2)
  290. i3.send_keys(image3)
  291. filter = self.find_element_by_name("filter_type")
  292. filter.value_of_css_property(0)
  293. pre = self.find_element_by_name("add_photo_done")
  294. pre.click()
  295. m = self.find_element_by_name("xc_message")
  296. m.send_keys(text)
  297. vp = self.find_element_by_name("view_post")
  298. vp.click()
  299. return True
  300. def commentInPost(self, postUrl, text):
  301. '''Comment a text(str) in a post(str)'''
  302. try:
  303. self.get(postUrl)
  304. tb = self.find_element_by_name("comment_text")
  305. tb.send_keys(text)
  306. tb.send_keys(Keys.TAB, Keys.ENTER)
  307. # _enter = self.find_element_by_xpath('//*[@id="u_0_3"]/tbody/tr/td[2]/div/input').click()
  308. return
  309. except Exception as e:
  310. print("Can't comment in ", postUrl, "\n->", e)
  311. def goToPost(self, postUrl):
  312. '''go to post in a group'''
  313. try:
  314. self.get(postUrl)
  315. # tb = self.find_element_by_name("comment_text")
  316. # tb.send_keys(text)
  317. # tb.send_keys(Keys.TAB, Keys.ENTER)
  318. return
  319. except Exception as e:
  320. print("Can't comment in ", postUrl, "\n->", e)
  321. def goToGroup(self, groupurl):
  322. try:
  323. self.get(groupurl)
  324. print('go to group: ', groupurl)
  325. except Exception as e:
  326. print(str(e))
  327. def getComments(self, postUrl):
  328. self.get(postUrl)
  329. gc = []
  330. for i in self.find_elements_by_tag_name('div'):
  331. if i not in gc:
  332. gc.append(i)
  333. return gc[0].text.splitlines()
  334. def getGroupMembers(self, url, deep=3, start=0):
  335. '''Return a list of members of a group(url) as a list:Person iterat deep(int) times'''
  336. seeMembersUrl = url + "?view=members&amp;refid=18"
  337. groupId = url.split("groups/")[1]
  338. step = 28
  339. r = "https://mbasic.facebook.com/browse/group/members/?id=$GROUPID$&start=$n$"
  340. rg = r.replace("$GROUPID$", groupId)
  341. members = []
  342. for d in range(start, start + deep):
  343. url = rg.replace("$n$", str(d * 30))
  344. self.get(url)
  345. # print(self.current_url)
  346. p = self.find_elements_by_class_name("p") # BK cada profile
  347. for b in p:
  348. person = Person()
  349. h3 = b.find_elements_by_tag_name("h3")
  350. person.name = h3[0].text
  351. person.profileLink = h3[0].find_element_by_tag_name(
  352. "a").get_attribute('href')
  353. try:
  354. person.addLink = b.find_elements_by_tag_name(
  355. "a")[1].get_attribute('href') # puede haber error
  356. except Exception:
  357. # print("No Addlink")
  358. pass
  359. members.append(person)
  360. # more = self.find_element_by_id("m_more_item").find_element_by_tag_name("a").get_attribute('href')
  361. # self.get(more)
  362. # print(more)
  363. # print(len(members))
  364. return members
  365. def sendFriendRequest(self, url):
  366. '''Send a friend request to a profile(str)'''
  367. self.get(url)
  368. try:
  369. bz = self.find_element_by_class_name("bz")
  370. l = bz.get_attribute('href')
  371. self.get(l)
  372. return True
  373. except Exception:
  374. # print("Can't add friend")
  375. return False
  376. def messageToUrl(self, url, text):
  377. '''Message a profile/fanpage (str) with text(str)'''
  378. self.get(url)
  379. name = self.title
  380. try:
  381. mb = self.find_elements_by_class_name("bx")
  382. except NoSuchElementException:
  383. print("Can't message to ", name)
  384. return False
  385. mm = None
  386. for m in mb:
  387. if "messages" in m.get_attribute('href'):
  388. mm = m.get_attribute('href')
  389. break
  390. self.get(mm)
  391. b = self.find_element_by_name("body")
  392. b.send_keys(text)
  393. self.find_element_by_name("Send").click()
  394. return True
  395. def getGroups(self):
  396. '''
  397. Return a list of url of the groups your account belong to'''
  398. url = "https://m.facebook.com/groups/?seemore"
  399. # g = {"name": ("url", 0)}
  400. g = dict()
  401. self.get(url)
  402. br = self.find_elements_by_class_name("br")
  403. for b in br:
  404. try:
  405. notis = int(b.text[-2:])
  406. group_name = b.text[:-2]
  407. except ValueError:
  408. group_name = b.text
  409. notis = 0
  410. try:
  411. link = b.find_element_by_tag_name("a").get_attribute('href')
  412. g[group_name] = (mfacebookToBasic(link), notis)
  413. except Exception as dummy:
  414. print("Can't get group link")
  415. return g
  416. def getSuggestedGroups(self, sendrequest=False):
  417. '''
  418. Return a list of suggested groups and optionally send a request to join'''
  419. url = "https://m.facebook.com/groups/"
  420. g = dict()
  421. self.get(url)
  422. bq = self.find_elements_by_class_name("bq")[-1]
  423. li = bq.find_elements_by_tag_name("li")
  424. for l in li:
  425. nombre = l.find_elements_by_tag_name(
  426. "td")[0].find_elements_by_tag_name("a")[0].text
  427. description = l.find_elements_by_tag_name(
  428. "td")[0].find_elements_by_class_name("bx")[0].text
  429. linkToGroup = l.find_elements_by_tag_name(
  430. "td")[0].find_element_by_tag_name("a").get_attribute('href')
  431. linkToRequest = l.find_elements_by_tag_name(
  432. "td")[-1].find_element_by_tag_name("a").get_attribute('href')
  433. g[nombre] = (description, linkToGroup, linkToRequest)
  434. if sendrequest:
  435. for r in g:
  436. try:
  437. self.get(g[r][2])
  438. print("Request to group: ", r)
  439. except Exception:
  440. print("Fail to send request to: ", r)
  441. return g
  442. def getPostInProfile(
  443. self,
  444. profileURL,
  445. deep=100,
  446. moreText="Mostrar",
  447. sharedText=(
  448. "shared",
  449. "comparti",
  450. "compartio")):
  451. '''Return a list of Posts in a profile/fanpage , setup the "moreText" using your language, theres not elegant way to handle that'''
  452. pList = list()
  453. self.get(profileURL)
  454. # DEEP1
  455. n = 0
  456. for d in range(deep):
  457. try:
  458. for i in (3, 4, 5, 6, 7):
  459. try:
  460. e = self.find_element_by_id("u_0_" + str(i))
  461. tU = str(e.text)
  462. except Exception:
  463. continue
  464. try:
  465. tspl = tU.split(self.title)[1].split("\n")[:-3]
  466. except IndexError:
  467. continue
  468. tFi = ""
  469. for k in tspl:
  470. tFi += k
  471. if sharedText[0] in tFi or sharedText[1] in tFi or sharedText[2] in tFi:
  472. continue
  473. if tFi not in pList:
  474. pList.append(tFi)
  475. n += 1
  476. print(n, "-\n", tFi)
  477. else:
  478. continue
  479. # press more
  480. al = self.find_element_by_partial_link_text(moreText)
  481. link = al.get_attribute('href')
  482. self.get(link)
  483. except BaseException:
  484. pass
  485. return pList
  486. #-------------------------------------------------------------------------------
  487. # if __name__ == '__main__':
  488. # bot = FacebookBot()
  489. # try:
  490. # bot.login('deeejas@gmail.com', 'italotrance')
  491. # # _posts = bot.getPostInGroup('https://mbasic.facebook.com/groups/106321362854637?refid=18&__tn__=C-R', deep=2
  492. # # _posts = bot.getPostInGroup('https://mbasic.facebook.com/groups/2121044018158040?refid=27', deep=2)
  493. # # bot.postInGroup('https://mbasic.facebook.com/groups/2121044018158040?refid=27', 'foci november 22')
  494. # _comment = True
  495. # gr_url = 'https://mbasic.facebook.com/groups/106321362854637?refid=18&__tn__=C-R'
  496. #
  497. # while True:
  498. # if not _comment: print('I : comment was inserted')
  499. # if dt.today().weekday() == 0 and _comment:
  500. # print('verifying post')
  501. # bot.refresh()
  502. # sleep(1)
  503. # _posts = bot.getPostInGroup(gr_url, deep=1)
  504. # sleep(2)
  505. # for i in _posts:
  506. # if re.search('jus[a-z]*|min[a-z]*|hr[a-z]*', i.time): # and re.search('foc[a-z]*', i.text):
  507. # print(i.posterName, i.time, i.text, i.numComents)
  508. # # pc = bot.getComments(i.linkToComment)
  509. # # print(pc)
  510. # # for i in pc:
  511. # # print(i.text)
  512. # bot.commentInPost(i.linkToComment, '+1')
  513. # print('post commented')
  514. # _comment = False
  515. # count_down(60, 'm', 'down')
  516. # else:
  517. # print('I : check on next monday')
  518. # count_down(3600, 'h', 'down')
  519. # except KeyboardInterrupt:
  520. # bot.logout()
  521. #-------------------------------------------------------------------------------