parser.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. #!/usr/bin/python3
  2. import sys
  3. import re
  4. import newspaper
  5. import pymongo
  6. import htmlmin
  7. import feedparser
  8. import datetime
  9. import threading
  10. from queue import Queue
  11. from frontpage import FrontPage
  12. from newspaper import Article
  13. from db import db
  14. from source import Source
  15. class LinkList():
  16. def __init__(self,url,selector=None,rss=False):
  17. self.links=[]
  18. if rss:
  19. feed = feedparser.parse(url)
  20. #print(feed["bozo"]) FIXME: If bozo==1 => error
  21. self.links=[i["link"] for i in feed["items"]]
  22. print(self.links)
  23. else:
  24. if selector is None:
  25. #s=newspaper.build(url,language="en",memoize_articles=False) #memoize puede salvarme la vida
  26. s = newspaper.Source(url,memoize_articles=False)
  27. s.download()
  28. s.parse()
  29. s.set_categories()
  30. s.download_categories()
  31. s.parse_categories()
  32. s.generate_articles()
  33. self.links=list(set([a.url for a in s.articles])) #avoid dupes
  34. else:
  35. f=FrontPage(url,selector)
  36. self.links=f.links
  37. self.links=self.purgeLinks(self.links)
  38. def purgeLinks(self,l):
  39. return [ sanitizeUrl(link) for link in l if not "presslist" in link.lower() and not "videolist" in link.lower() ]
  40. class News():
  41. r=re.compile(r"hours? ago|yesterday|today|last week|month",flags=re.IGNORECASE)
  42. r_noise=re.compile(r"posted|Product|Google",flags=re.IGNORECASE)
  43. URL=""
  44. AUTHORS=[]
  45. SCRAP_DATE=None
  46. PUBLISH_DATE=None
  47. SUMMARY=""
  48. TEXT=""
  49. HTML=""
  50. ERROR=False
  51. SOURCE=""
  52. def __init__(self,url,source,lang="en"):
  53. url=sanitizeUrl(url)
  54. self.URL=url
  55. self.SOURCE=source
  56. a = Article(url, language=lang,keep_article_html=True)
  57. a.download()
  58. a.parse()
  59. a.nlp()
  60. a.authors=self.dedup([self.fix_author(value) for value in a.authors if not self.isComment(value) and not self.isNoise(value)])
  61. self.SCRAP_DATE=datetime.datetime.now()
  62. self.AUTHORS=a.authors
  63. self.PUBLISH_DATE=a.publish_date
  64. self.SUMMARY=a.summary
  65. self.TEXT=a.text
  66. self.HTML=htmlmin.minify(a.article_html,remove_empty_space=True)
  67. def get(self):
  68. return {
  69. "url": self.URL,
  70. "source": self.SOURCE,
  71. "authors": self.AUTHORS,
  72. "scrap_date": self.SCRAP_DATE,
  73. "publish_date": self.PUBLISH_DATE,
  74. "summary": self.SUMMARY,
  75. "text": self.TEXT,
  76. "html": self.HTML
  77. }
  78. def dedup(self,val):
  79. return list(set(val))
  80. def isNoise(self,v):
  81. if self.r_noise.match(v):
  82. return True
  83. return False
  84. def isComment(self,v):
  85. if self.r.match(v):
  86. return True
  87. return False
  88. def fix_author(self,a):
  89. return a.replace("_", " ").lower()
  90. unsharer=re.compile(r"(\?share=|#).+$",flags=re.IGNORECASE)
  91. def sanitizeUrl(url):
  92. global unsharer
  93. ret = re.sub(unsharer, "",url)
  94. return ret
  95. def sanitizeSelector(s):
  96. s=s.replace(">a","> a")
  97. if re.match(r'=\w+\]',s) is None:
  98. return s
  99. ret=re.sub(r"=(\w+)]", r'="\1"]', s)
  100. return ret
  101. def parseSource(s):
  102. sel=None
  103. rss=False
  104. if "selector" in s:
  105. sel=s["selector"]
  106. if "rss" in s:
  107. rss=bool(["rss"])
  108. l=LinkList(s["link"],sel,rss=rss)
  109. if l is not None:
  110. for a in l.links:
  111. if not d.article_exists(a):
  112. print(a)
  113. q.put(a)
  114. print(len(l.links))
  115. num_worker_threads=8
  116. threads=[]
  117. for i in range(num_worker_threads):
  118. t = threading.Thread(target=news_worker,args=[s["_id"]])
  119. t.daemon=True
  120. t.start()
  121. threads.append(t)
  122. q.join()
  123. for i in range(num_worker_threads):
  124. q.put(None)
  125. for t in threads:
  126. t.join()
  127. print("Finished parsing %s" %s)
  128. def news_worker(source_id):
  129. while True:
  130. item = q.get()
  131. if item is None:
  132. break
  133. n=News(item,source_id)
  134. print("[Thread %s] %s" % (threading.current_thread(),n.URL))
  135. d.insert_article(n.get())
  136. q.task_done()
  137. q=Queue()
  138. d=db()
  139. for s in d.sources():
  140. print(s["name"])
  141. parseSource(s)
  142. break