parser.py 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. #!/usr/bin/python3
  2. import threading
  3. from queue import Queue
  4. from db import db
  5. from source import Source
  6. from linklist import LinkList
  7. from news import News
  8. from paid_parser import PaidParser
  9. from time import strftime,time
  10. from multiprocessing import Pool
  11. import sys
  12. from analytics import post_data
  13. def parseSource(s):
  14. init = time()
  15. q = Queue()
  16. sel = None
  17. rss = False
  18. if "selector" in s:
  19. sel = s["selector"]
  20. if "rss" in s:
  21. rss = bool(s["rss"])
  22. l = LinkList(s["link"], sel, rss=rss)
  23. d = db()
  24. kw = d.get_keywords(s["category"])
  25. new_articles = 0
  26. if l is not None:
  27. for a in l.links:
  28. if not d.article_exists(a.lower(), s["_id"]):
  29. q.put(a)
  30. # print("[%s][Source] %s: %d/%d new/total articles" %
  31. # (strftime("%H:%M:%S"), s["name"], q.qsize(), len(l.links)))
  32. new_articles = q.qsize()
  33. if not q.empty():
  34. num_worker_threads = min(5, q.qsize())
  35. threads = []
  36. for _ in range(num_worker_threads):
  37. t = threading.Thread(target=news_worker, args=[s, kw, d, q])
  38. # source, keywords, db, queue
  39. t.daemon = True
  40. t.start()
  41. threads.append(t)
  42. # print("Waiting for %d queue elements" % q.qsize())
  43. q.join() # block until all tasks are done
  44. # print("Finished waiting for the queue")
  45. for _ in range(num_worker_threads):
  46. # put num_worker empty jobs so
  47. # each worker can work once
  48. q.put(None)
  49. for t in threads:
  50. t.join(10)
  51. ex_time = time()-init
  52. print("[%s][Source] %s => Finished parsing, %d/%d new articles, in %0.3fsec" %
  53. (strftime("%H:%M:%S"),
  54. s["name"], new_articles, len(l.links), ex_time))
  55. sys.stdout.flush()
  56. return (ex_time, len(l.links), s["name"], new_articles)
  57. def news_worker(source, kw, d, q):
  58. source_id = source["_id"]
  59. source_name = source["name"]
  60. source_category = source["category"]
  61. paid = False
  62. if "paid" in source and source["paid"]:
  63. paid = True
  64. # tname = threading.current_thread().name
  65. while True:
  66. try:
  67. item = q.get(timeout=5)
  68. except:
  69. # print("Failed to get item")
  70. q.task_done()
  71. break
  72. if item is None:
  73. q.task_done()
  74. break
  75. # print("[Thread %s] %s" % (tname,item))
  76. try:
  77. html = None
  78. if paid:
  79. p = PaidParser(item)
  80. html = p.html
  81. n = News(item, source_id, source_name,
  82. source_category, kw, html=html)
  83. # print("[Thread %s] Finished" % tname)
  84. d.insert_article(n.get())
  85. except Exception as e:
  86. print("#### EXCEPTION ########")
  87. print(e)
  88. print(item)
  89. print("#### END EXCEPTION ####")
  90. finally:
  91. q.task_done()
  92. # TODO influx start
  93. post_data('event', 'start')
  94. start = time()
  95. sources = db().sources()
  96. db().purge_error()
  97. post_data('event', {'type': 'purge_complete'}, 1)
  98. pool = Pool(processes=4)
  99. ret = pool.map(parseSource, sources)
  100. new = sum([r[3] for r in ret])
  101. tot = sum([r[1] for r in ret])
  102. post_data('value', {'type': 'new'}, new)
  103. post_data('value', {'type': 'total'}, tot)
  104. # TODO influx source new
  105. # TODO influx source total
  106. # n = sum(ret)
  107. # sret = sorted(ret, key=lambda tup: tup[0])
  108. # print(sret)
  109. print("[%s] %d/%d new articles, total time %d sec" %
  110. (strftime("%H:%M:%S"), new, tot, time()-start))
  111. print("#" * 75)
  112. # TODO influx end
  113. post_data('event', 'end')