scrapegraphai 1.2.1__tar.gz → 1.2.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (253) hide show
  1. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/CHANGELOG.md +7 -0
  2. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/PKG-INFO +2 -2
  3. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/docs/source/getting_started/installation.rst +2 -4
  4. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/manual deployment/deploy_on_pip.sh +0 -3
  5. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/pyproject.toml +3 -4
  6. scrapegraphai-1.2.2/scrapegraphai/builders/__init__.py +5 -0
  7. scrapegraphai-1.2.2/scrapegraphai/builders/graph_builder.py +168 -0
  8. scrapegraphai-1.2.2/scrapegraphai/docloaders/__init__.py +3 -0
  9. scrapegraphai-1.2.2/scrapegraphai/docloaders/chromium.py +126 -0
  10. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/scrapegraphai/graphs/__init__.py +1 -0
  11. scrapegraphai-1.2.2/scrapegraphai/graphs/deep_scraper_graph.py +116 -0
  12. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/scrapegraphai/graphs/omni_search_graph.py +2 -2
  13. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/scrapegraphai/graphs/search_graph.py +2 -2
  14. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/scrapegraphai/graphs/smart_scraper_graph.py +1 -1
  15. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/scrapegraphai/nodes/__init__.py +1 -2
  16. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/scrapegraphai/nodes/fetch_node.py +0 -1
  17. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/scrapegraphai/nodes/generate_answer_node.py +1 -1
  18. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/scrapegraphai/nodes/merge_answers_node.py +2 -2
  19. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/scrapegraphai/nodes/robots_node.py +4 -8
  20. scrapegraphai-1.2.1/examples/custom_graph_domtree.py +0 -171
  21. scrapegraphai-1.2.1/examples/domtree_example.py +0 -99
  22. scrapegraphai-1.2.1/examples/faiss_vector.py +0 -34
  23. scrapegraphai-1.2.1/html_structure +0 -256
  24. scrapegraphai-1.2.1/html_structure.png +0 -0
  25. scrapegraphai-1.2.1/manual deployment/rye_update.sh +0 -7
  26. scrapegraphai-1.2.1/scrapegraphai/nodes/blocks_identifier.py +0 -57
  27. scrapegraphai-1.2.1/scrapegraphai/nodes/search_node_with_context.py +0 -114
  28. scrapegraphai-1.2.1/scrapegraphai/utils/aaa.py +0 -212
  29. scrapegraphai-1.2.1/scrapegraphai/utils/asdt.py +0 -156
  30. scrapegraphai-1.2.1/scrapegraphai/utils/tree_base.py +0 -59
  31. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/.gitattributes +0 -0
  32. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  33. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/.github/ISSUE_TEMPLATE/custom.md +0 -0
  34. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  35. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/.github/workflows/codeql.yml +0 -0
  36. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/.github/workflows/dependency-review.yml +0 -0
  37. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/.github/workflows/pylint.yml +0 -0
  38. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/.github/workflows/python-publish.yml +0 -0
  39. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/.github/workflows/release.yml +0 -0
  40. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/.gitignore +0 -0
  41. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/.releaserc.yml +0 -0
  42. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/CODE_OF_CONDUCT.md +0 -0
  43. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/CONTRIBUTING.md +0 -0
  44. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/Dockerfile +0 -0
  45. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/LICENSE +0 -0
  46. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/README.md +0 -0
  47. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/SECURITY.md +0 -0
  48. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/citation.cff +0 -0
  49. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/docker-compose.yml +0 -0
  50. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/docs/Makefile +0 -0
  51. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/docs/README.md +0 -0
  52. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/docs/assets/apikey_1.png +0 -0
  53. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/docs/assets/apikey_2.png +0 -0
  54. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/docs/assets/apikey_3.png +0 -0
  55. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/docs/assets/apikey_4.png +0 -0
  56. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/docs/assets/codespaces-badge.png +0 -0
  57. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/docs/assets/logo_authors.png +0 -0
  58. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/docs/assets/omniscrapergraph.png +0 -0
  59. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/docs/assets/omnisearchgraph.png +0 -0
  60. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/docs/assets/project_overview_diagram.fig +0 -0
  61. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/docs/assets/project_overview_diagram.png +0 -0
  62. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/docs/assets/scrapegraphai_logo.png +0 -0
  63. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/docs/assets/searchgraph.png +0 -0
  64. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/docs/assets/serp_api_logo.png +0 -0
  65. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/docs/assets/smartscrapergraph.png +0 -0
  66. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/docs/assets/speechgraph.png +0 -0
  67. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/docs/make.bat +0 -0
  68. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/docs/source/conf.py +0 -0
  69. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/docs/source/getting_started/examples.rst +0 -0
  70. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/docs/source/index.rst +0 -0
  71. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/docs/source/introduction/contributing.rst +0 -0
  72. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/docs/source/introduction/overview.rst +0 -0
  73. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/docs/source/modules/modules.rst +0 -0
  74. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/docs/source/modules/scrapegraphai.graphs.rst +0 -0
  75. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/docs/source/modules/scrapegraphai.nodes.rst +0 -0
  76. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/docs/source/modules/scrapegraphai.rst +0 -0
  77. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/docs/source/scrapers/benchmarks.rst +0 -0
  78. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/docs/source/scrapers/graph_config.rst +0 -0
  79. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/docs/source/scrapers/graphs.rst +0 -0
  80. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/docs/source/scrapers/llm.rst +0 -0
  81. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/anthropic/smart_scraper_haiku.py +0 -0
  82. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/azure/inputs/books.xml +0 -0
  83. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/azure/inputs/example.json +0 -0
  84. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/azure/inputs/username.csv +0 -0
  85. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/azure/json_scraper_azure.py +0 -0
  86. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/azure/search_graph_azure.py +0 -0
  87. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/azure/smart_scraper_azure_openai.py +0 -0
  88. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/azure/xml_scraper_azure.py +0 -0
  89. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/bedrock/smart_scraper_bedrock.py +0 -0
  90. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/benchmarks/GenerateScraper/.env.example +0 -0
  91. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/benchmarks/GenerateScraper/Readme.md +0 -0
  92. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/benchmarks/GenerateScraper/benchmark_docker.py +0 -0
  93. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/benchmarks/GenerateScraper/benchmark_groq.py +0 -0
  94. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/benchmarks/GenerateScraper/benchmark_llama3.py +0 -0
  95. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/benchmarks/GenerateScraper/benchmark_mistral.py +0 -0
  96. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/benchmarks/GenerateScraper/benchmark_openai_gpt35.py +0 -0
  97. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/benchmarks/GenerateScraper/benchmark_openai_gpt4.py +0 -0
  98. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/benchmarks/GenerateScraper/inputs/example_1.txt +0 -0
  99. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/benchmarks/GenerateScraper/inputs/example_2.txt +0 -0
  100. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/benchmarks/SmartScraper/.env.example +0 -0
  101. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/benchmarks/SmartScraper/Readme.md +0 -0
  102. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/benchmarks/SmartScraper/benchmark_docker.py +0 -0
  103. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/benchmarks/SmartScraper/benchmark_groq.py +0 -0
  104. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/benchmarks/SmartScraper/benchmark_llama3.py +0 -0
  105. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/benchmarks/SmartScraper/benchmark_mistral.py +0 -0
  106. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/benchmarks/SmartScraper/benchmark_openai_gpt35.py +0 -0
  107. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/benchmarks/SmartScraper/benchmark_openai_gpt4.py +0 -0
  108. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/benchmarks/SmartScraper/inputs/example_1.txt +0 -0
  109. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/benchmarks/SmartScraper/inputs/example_2.txt +0 -0
  110. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/benchmarks/readme.md +0 -0
  111. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/deepseek/.env.example +0 -0
  112. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/deepseek/csv_scraper_deepseek.py +0 -0
  113. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/deepseek/inputs/books.xml +0 -0
  114. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/deepseek/inputs/example.json +0 -0
  115. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/deepseek/inputs/username.csv +0 -0
  116. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/deepseek/json_scraper_deepseek.py +0 -0
  117. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/deepseek/script_generator_deepseek.py +0 -0
  118. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/deepseek/search_graph_deepseek.py +0 -0
  119. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/deepseek/smart_scarper_deepseek.py +0 -0
  120. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/deepseek/xml_scraper_deepseek.py +0 -0
  121. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/gemini/.env.example +0 -0
  122. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/gemini/csv_scraper_gemini.py +0 -0
  123. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/gemini/custom_graph_gemini.py +0 -0
  124. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/gemini/inputs/books.xml +0 -0
  125. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/gemini/inputs/example.json +0 -0
  126. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/gemini/inputs/plain_html_example.txt +0 -0
  127. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/gemini/inputs/username.csv +0 -0
  128. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/gemini/json_scraper_gemini.py +0 -0
  129. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/gemini/readme.md +0 -0
  130. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/gemini/scrape_plain_text_gemini.py +0 -0
  131. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/gemini/scrape_xml_gemini.py +0 -0
  132. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/gemini/script_generator_gemini.py +0 -0
  133. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/gemini/search_graph_gemini.py +0 -0
  134. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/gemini/smart_scraper_gemini.py +0 -0
  135. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/gemini/xml_scraper_openai.py +0 -0
  136. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/groq/.env.example +0 -0
  137. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/groq/search_graph_groq_openai.py +0 -0
  138. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/groq/smart_scraper_groq_ollama.py +0 -0
  139. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/groq/smart_scraper_groq_openai.py +0 -0
  140. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/huggingfacehub/smart_scraper_huggingfacehub.py +0 -0
  141. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/local_models/csv_scraper_ollama.py +0 -0
  142. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/local_models/inputs/books.xml +0 -0
  143. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/local_models/inputs/example.json +0 -0
  144. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/local_models/inputs/plain_html_example.txt +0 -0
  145. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/local_models/inputs/username.csv +0 -0
  146. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/local_models/json_scraper_ollama.py +0 -0
  147. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/local_models/scrape_plain_text_ollama.py +0 -0
  148. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/local_models/scrape_xml_ollama.py +0 -0
  149. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/local_models/script_generator_ollama.py +0 -0
  150. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/local_models/search_graph_ollama.py +0 -0
  151. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/local_models/smart_scraper_ollama.py +0 -0
  152. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/local_models/xml_scraper_ollama.py +0 -0
  153. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/mixed_models/.env.example +0 -0
  154. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/mixed_models/inputs/books.xml +0 -0
  155. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/mixed_models/inputs/example.json +0 -0
  156. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/mixed_models/inputs/plain_html_example.txt +0 -0
  157. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/mixed_models/readme.md +0 -0
  158. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/mixed_models/search_graph_groq_ollama.py +0 -0
  159. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/mixed_models/smart_scraper_mixed.py +0 -0
  160. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/openai/.env.example +0 -0
  161. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/openai/csv_scraper_openai.py +0 -0
  162. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/openai/custom_graph_openai.py +0 -0
  163. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/openai/deep_scraper_openai.py +0 -0
  164. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/openai/inputs/books.xml +0 -0
  165. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/openai/inputs/example.json +0 -0
  166. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/openai/inputs/plain_html_example.txt +0 -0
  167. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/openai/inputs/username.csv +0 -0
  168. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/openai/json_scraper_openai.py +0 -0
  169. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/openai/omni_scraper_openai.py +0 -0
  170. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/openai/omni_search_graph_openai.py +0 -0
  171. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/openai/readme.md +0 -0
  172. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/openai/scrape_plain_text_openai.py +0 -0
  173. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/openai/script_generator_openai.py +0 -0
  174. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/openai/search_graph_openai.py +0 -0
  175. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/openai/smart_scraper_openai.py +0 -0
  176. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/openai/speech_graph_openai.py +0 -0
  177. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/openai/xml_scraper_openai.py +0 -0
  178. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/readme.md +0 -0
  179. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/single_node/fetch_node.py +0 -0
  180. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/single_node/image2text_node.py +0 -0
  181. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/examples/single_node/robot_node.py +0 -0
  182. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/manual deployment/commit_and_push.sh +0 -0
  183. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/manual deployment/commit_and_push_with_tests.sh +0 -0
  184. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/readthedocs.yml +0 -0
  185. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/requirements-dev.txt +0 -0
  186. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/requirements.txt +0 -0
  187. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/scrapegraphai/__init__.py +0 -0
  188. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/scrapegraphai/graphs/abstract_graph.py +0 -0
  189. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/scrapegraphai/graphs/base_graph.py +0 -0
  190. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/scrapegraphai/graphs/csv_scraper_graph.py +0 -0
  191. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/scrapegraphai/graphs/json_scraper_graph.py +0 -0
  192. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/scrapegraphai/graphs/omni_scraper_graph.py +0 -0
  193. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/scrapegraphai/graphs/pdf_scraper_graph.py +0 -0
  194. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/scrapegraphai/graphs/script_creator_graph.py +0 -0
  195. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/scrapegraphai/graphs/speech_graph.py +0 -0
  196. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/scrapegraphai/graphs/xml_scraper_graph.py +0 -0
  197. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/scrapegraphai/helpers/__init__.py +0 -0
  198. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/scrapegraphai/helpers/models_tokens.py +0 -0
  199. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/scrapegraphai/helpers/nodes_metadata.py +0 -0
  200. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/scrapegraphai/helpers/robots.py +0 -0
  201. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/scrapegraphai/helpers/schemas.py +0 -0
  202. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/scrapegraphai/models/__init__.py +0 -0
  203. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/scrapegraphai/models/anthropic.py +0 -0
  204. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/scrapegraphai/models/azure_openai.py +0 -0
  205. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/scrapegraphai/models/bedrock.py +0 -0
  206. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/scrapegraphai/models/deepseek.py +0 -0
  207. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/scrapegraphai/models/gemini.py +0 -0
  208. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/scrapegraphai/models/groq.py +0 -0
  209. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/scrapegraphai/models/hugging_face.py +0 -0
  210. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/scrapegraphai/models/ollama.py +0 -0
  211. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/scrapegraphai/models/openai.py +0 -0
  212. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/scrapegraphai/models/openai_itt.py +0 -0
  213. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/scrapegraphai/models/openai_tts.py +0 -0
  214. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/scrapegraphai/nodes/base_node.py +0 -0
  215. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/scrapegraphai/nodes/conditional_node.py +0 -0
  216. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/scrapegraphai/nodes/generate_answer_csv_node.py +0 -0
  217. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/scrapegraphai/nodes/generate_answer_omni_node.py +0 -0
  218. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/scrapegraphai/nodes/generate_answer_pdf_node.py +0 -0
  219. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/scrapegraphai/nodes/generate_scraper_node.py +0 -0
  220. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/scrapegraphai/nodes/get_probable_tags_node.py +0 -0
  221. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/scrapegraphai/nodes/graph_iterator_node.py +0 -0
  222. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/scrapegraphai/nodes/image_to_text_node.py +0 -0
  223. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/scrapegraphai/nodes/parse_node.py +0 -0
  224. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/scrapegraphai/nodes/rag_node.py +0 -0
  225. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/scrapegraphai/nodes/search_internet_node.py +0 -0
  226. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/scrapegraphai/nodes/search_link_node.py +0 -0
  227. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/scrapegraphai/nodes/text_to_speech_node.py +0 -0
  228. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/scrapegraphai/utils/__init__.py +0 -0
  229. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/scrapegraphai/utils/cleanup_html.py +0 -0
  230. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/scrapegraphai/utils/convert_to_csv.py +0 -0
  231. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/scrapegraphai/utils/convert_to_json.py +0 -0
  232. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/scrapegraphai/utils/parse_state_keys.py +0 -0
  233. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/scrapegraphai/utils/prettify_exec_info.py +0 -0
  234. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/scrapegraphai/utils/proxy_rotation.py +0 -0
  235. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/scrapegraphai/utils/research_web.py +0 -0
  236. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/scrapegraphai/utils/save_audio_from_bytes.py +0 -0
  237. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/scrapegraphai/utils/sys_dynamic_import.py +0 -0
  238. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/scrapegraphai/utils/token_calculator.py +0 -0
  239. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/tests/Readme.md +0 -0
  240. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/tests/graphs/inputs/books.xml +0 -0
  241. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/tests/graphs/inputs/example.json +0 -0
  242. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/tests/graphs/inputs/plain_html_example.txt +0 -0
  243. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/tests/graphs/inputs/username.csv +0 -0
  244. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/tests/graphs/scrape_json_ollama.py +0 -0
  245. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/tests/graphs/scrape_plain_text_llama3_test.py +0 -0
  246. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/tests/graphs/scrape_plain_text_mistral_test.py +0 -0
  247. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/tests/graphs/scrape_xml_ollama_test.py +0 -0
  248. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/tests/graphs/script_generator_test.py +0 -0
  249. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/tests/graphs/smart_scraper_ollama_test.py +0 -0
  250. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/tests/nodes/fetch_node_test.py +0 -0
  251. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/tests/nodes/robot_node_test.py +0 -0
  252. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/tests/utils/test_proxy_rotation.py +0 -0
  253. {scrapegraphai-1.2.1 → scrapegraphai-1.2.2}/tests/utils/test_sys_dynamic_import.py +0 -0
@@ -1,3 +1,10 @@
1
+ ## [1.2.2](https://github.com/VinciGit00/Scrapegraph-ai/compare/v1.2.1...v1.2.2) (2024-05-15)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * come back to the old version ([cc5adef](https://github.com/VinciGit00/Scrapegraph-ai/commit/cc5adefd29eb2d0d7127515c4a4a72eabbc7eaa8))
7
+
1
8
  ## [1.2.1](https://github.com/VinciGit00/Scrapegraph-ai/compare/v1.2.0...v1.2.1) (2024-05-15)
2
9
 
3
10
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: scrapegraphai
3
- Version: 1.2.1
3
+ Version: 1.2.2
4
4
  Summary: A web scraping library based on LangChain which uses LLM and direct graph logic to create scraping pipelines.
5
5
  Author-email: Marco Vinciguerra <mvincig11@gmail.com>, Marco Perini <perinim.98@gmail.com>, Lorenzo Padoan <lorenzo.padoan977@gmail.com>
6
6
  License-Expression: MIT
@@ -10,7 +10,7 @@ Classifier: Intended Audience :: Developers
10
10
  Classifier: Operating System :: OS Independent
11
11
  Classifier: Programming Language :: Python :: 3
12
12
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
13
- Requires-Python: <3.12,>=3.9
13
+ Requires-Python: >=3.9
14
14
  Requires-Dist: beautifulsoup4==4.12.3
15
15
  Requires-Dist: faiss-cpu==1.8.0
16
16
  Requires-Dist: free-proxy==1.1.1
@@ -25,13 +25,11 @@ The library is available on PyPI, so it can be installed using the following com
25
25
 
26
26
  It is higly recommended to install the library in a virtual environment (conda, venv, etc.)
27
27
 
28
- If you clone the repository, you can install the library using `rye <https://rye-up.com/>`_. Follow the installation instruction from the website and then run:
28
+ If your clone the repository, you can install the library using `poetry <https://python-poetry.org/docs/>`_:
29
29
 
30
30
  .. code-block:: bash
31
31
 
32
- rye pin 3.10
33
- rye sync
34
- rye build
32
+ poetry install
35
33
 
36
34
  Additionally on Windows when using WSL
37
35
  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -2,9 +2,6 @@
2
2
  cd ..
3
3
 
4
4
  rye self update
5
-
6
- rye pin 3.10
7
-
8
5
  # Install dependencies using Poetry
9
6
  rye sync
10
7
 
@@ -1,7 +1,7 @@
1
1
  [project]
2
2
  name = "scrapegraphai"
3
3
 
4
- version = "1.2.1"
4
+ version = "1.2.2"
5
5
 
6
6
  description = "A web scraping library based on LangChain which uses LLM and direct graph logic to create scraping pipelines."
7
7
  authors = [
@@ -10,6 +10,7 @@ authors = [
10
10
  { name = "Lorenzo Padoan", email = "lorenzo.padoan977@gmail.com" }
11
11
  ]
12
12
  dependencies = [
13
+ # python = ">=3.9, <3.12"
13
14
  "langchain==0.1.15",
14
15
  "langchain-openai==0.1.6",
15
16
  "langchain-google-genai==1.0.3",
@@ -61,14 +62,12 @@ classifiers = [
61
62
  "Programming Language :: Python :: 3",
62
63
  "Operating System :: OS Independent",
63
64
  ]
64
- requires-python = ">= 3.9, < 3.12"
65
-
65
+ requires-python = ">= 3.9"
66
66
 
67
67
  [build-system]
68
68
  requires = ["hatchling"]
69
69
  build-backend = "hatchling.build"
70
70
 
71
-
72
71
  [tool.rye]
73
72
  managed = true
74
73
  dev-dependencies = [
@@ -0,0 +1,5 @@
1
+ """
2
+ __init__.py file for builders folder
3
+ """
4
+
5
+ from .graph_builder import GraphBuilder
@@ -0,0 +1,168 @@
1
+ """
2
+ GraphBuilder Module
3
+ """
4
+
5
+ from langchain_core.prompts import ChatPromptTemplate
6
+ from langchain.chains import create_extraction_chain
7
+ from ..models import OpenAI, Gemini
8
+ from ..helpers import nodes_metadata, graph_schema
9
+
10
+
11
+ class GraphBuilder:
12
+ """
13
+ GraphBuilder is a dynamic tool for constructing web scraping graphs based on user prompts.
14
+ It utilizes a natural language understanding model to interpret user prompts and
15
+ automatically generates a graph configuration for scraping web content.
16
+
17
+ Attributes:
18
+ prompt (str): The user's natural language prompt for the scraping task.
19
+ llm (ChatOpenAI): An instance of the ChatOpenAI class configured
20
+ with the specified llm_config.
21
+ nodes_description (str): A string description of all available nodes and their arguments.
22
+ chain (LLMChain): The extraction chain responsible for
23
+ processing the prompt and creating the graph.
24
+
25
+ Methods:
26
+ build_graph(): Executes the graph creation process based on the user prompt
27
+ and returns the graph configuration.
28
+ convert_json_to_graphviz(json_data): Converts a JSON graph configuration
29
+ to a Graphviz object for visualization.
30
+
31
+ Args:
32
+ prompt (str): The user's natural language prompt describing the desired scraping operation.
33
+ url (str): The target URL from which data is to be scraped.
34
+ llm_config (dict): Configuration parameters for the
35
+ language model, where 'api_key' is mandatory,
36
+ and 'model_name', 'temperature', and 'streaming' can be optionally included.
37
+
38
+ Raises:
39
+ ValueError: If 'api_key' is not included in llm_config.
40
+ """
41
+
42
+ def __init__(self, user_prompt: str, config: dict):
43
+ """
44
+ Initializes the GraphBuilder with a user prompt and language model configuration.
45
+ """
46
+ self.user_prompt = user_prompt
47
+ self.config = config
48
+ self.llm = self._create_llm(config["llm"])
49
+ self.nodes_description = self._generate_nodes_description()
50
+ self.chain = self._create_extraction_chain()
51
+
52
+ def _create_llm(self, llm_config: dict):
53
+ """
54
+ Creates an instance of the OpenAI class with the provided language model configuration.
55
+
56
+ Returns:
57
+ OpenAI: An instance of the OpenAI class.
58
+
59
+ Raises:
60
+ ValueError: If 'api_key' is not provided in llm_config.
61
+ """
62
+ llm_defaults = {
63
+ "temperature": 0,
64
+ "streaming": True
65
+ }
66
+ # Update defaults with any LLM parameters that were provided
67
+ llm_params = {**llm_defaults, **llm_config}
68
+ if "api_key" not in llm_params:
69
+ raise ValueError("LLM configuration must include an 'api_key'.")
70
+
71
+ # select the model based on the model name
72
+ if "gpt-" in llm_params["model"]:
73
+ return OpenAI(llm_params)
74
+ elif "gemini" in llm_params["model"]:
75
+ return Gemini(llm_params)
76
+ raise ValueError("Model not supported")
77
+
78
+ def _generate_nodes_description(self):
79
+ """
80
+ Generates a string description of all available nodes and their arguments.
81
+
82
+ Returns:
83
+ str: A string description of all available nodes and their arguments.
84
+ """
85
+
86
+ return "\n".join([
87
+ f"""- {node}: {data["description"]} (Type: {data["type"]},
88
+ Args: {", ".join(data["args"].keys())})"""
89
+ for node, data in nodes_metadata.items()
90
+ ])
91
+
92
+ def _create_extraction_chain(self):
93
+ """
94
+ Creates an extraction chain for processing the user prompt and
95
+ generating the graph configuration.
96
+
97
+ Returns:
98
+ LLMChain: An instance of the LLMChain class.
99
+ """
100
+
101
+ create_graph_prompt_template = """
102
+ You are an AI that designs direct graphs for web scraping tasks.
103
+ Your goal is to create a web scraping pipeline that is efficient and tailored to the user's requirements.
104
+ You have access to a set of default nodes, each with specific capabilities:
105
+
106
+ {nodes_description}
107
+
108
+ Based on the user's input: "{input}", identify the essential nodes required for the task and suggest a graph configuration that outlines the flow between the chosen nodes.
109
+ """.format(nodes_description=self.nodes_description, input="{input}")
110
+ extraction_prompt = ChatPromptTemplate.from_template(
111
+ create_graph_prompt_template)
112
+ return create_extraction_chain(prompt=extraction_prompt, schema=graph_schema, llm=self.llm)
113
+
114
+ def build_graph(self):
115
+ """
116
+ Executes the graph creation process based on the user prompt and
117
+ returns the graph configuration.
118
+
119
+ Returns:
120
+ dict: A JSON representation of the graph configuration.
121
+ """
122
+ return self.chain.invoke(self.user_prompt)
123
+
124
+ @staticmethod
125
+ def convert_json_to_graphviz(json_data, format: str = 'pdf'):
126
+ """
127
+ Converts a JSON graph configuration to a Graphviz object for visualization.
128
+
129
+ Args:
130
+ json_data (dict): A JSON representation of the graph configuration.
131
+
132
+ Returns:
133
+ graphviz.Digraph: A Graphviz object representing the graph configuration.
134
+ """
135
+ try:
136
+ import graphviz
137
+ except ImportError:
138
+ raise ImportError("The 'graphviz' library is required for this functionality. "
139
+ "Please install it from 'https://graphviz.org/download/'.")
140
+
141
+ graph = graphviz.Digraph(comment='ScrapeGraphAI Generated Graph', format=format,
142
+ node_attr={'color': 'lightblue2', 'style': 'filled'})
143
+
144
+ graph_config = json_data["text"][0]
145
+
146
+ # Retrieve nodes, edges, and the entry point from the JSON data
147
+ nodes = graph_config.get('nodes', [])
148
+ edges = graph_config.get('edges', [])
149
+ entry_point = graph_config.get('entry_point')
150
+
151
+ # Add nodes to the graph
152
+ for node in nodes:
153
+ # If this node is the entry point, use a double circle to denote it
154
+ if node['node_name'] == entry_point:
155
+ graph.node(node['node_name'], shape='doublecircle')
156
+ else:
157
+ graph.node(node['node_name'])
158
+
159
+ # Add edges to the graph
160
+ for edge in edges:
161
+ # An edge could potentially have multiple 'to' nodes if it's from a conditional node
162
+ if isinstance(edge['to'], list):
163
+ for to_node in edge['to']:
164
+ graph.edge(edge['from'], to_node)
165
+ else:
166
+ graph.edge(edge['from'], edge['to'])
167
+
168
+ return graph
@@ -0,0 +1,3 @@
1
+ """__init__.py file for docloaders folder"""
2
+
3
+ from .chromium import ChromiumLoader
@@ -0,0 +1,126 @@
1
+ import asyncio
2
+ import logging
3
+ from typing import Any, AsyncIterator, Iterator, List, Optional
4
+
5
+ from langchain_community.document_loaders.base import BaseLoader
6
+ from langchain_core.documents import Document
7
+
8
+ from ..utils import Proxy, dynamic_import, parse_or_search_proxy
9
+
10
+
11
+ logger = logging.getLogger(__name__)
12
+
13
+
14
+ class ChromiumLoader(BaseLoader):
15
+ """scrapes HTML pages from URLs using a (headless) instance of the
16
+ Chromium web driver with proxy protection
17
+
18
+ Attributes:
19
+ backend: The web driver backend library; defaults to 'playwright'.
20
+ browser_config: A dictionary containing additional browser kwargs.
21
+ headless: whether to run browser in headless mode.
22
+ proxy: A dictionary containing proxy settings; None disables protection.
23
+ urls: A list of URLs to scrape content from.
24
+ """
25
+
26
+ def __init__(
27
+ self,
28
+ urls: List[str],
29
+ *,
30
+ backend: str = "playwright",
31
+ headless: bool = True,
32
+ proxy: Optional[Proxy] = None,
33
+ **kwargs: Any,
34
+ ):
35
+ """Initialize the loader with a list of URL paths.
36
+
37
+ Args:
38
+ backend: The web driver backend library; defaults to 'playwright'.
39
+ headless: whether to run browser in headless mode.
40
+ proxy: A dictionary containing proxy information; None disables protection.
41
+ urls: A list of URLs to scrape content from.
42
+ kwargs: A dictionary containing additional browser kwargs.
43
+
44
+ Raises:
45
+ ImportError: If the required backend package is not installed.
46
+ """
47
+ message = (
48
+ f"{backend} is required for ChromiumLoader. "
49
+ f"Please install it with `pip install {backend}`."
50
+ )
51
+
52
+ dynamic_import(backend, message)
53
+
54
+ self.backend = backend
55
+ self.browser_config = kwargs
56
+ self.headless = headless
57
+ self.proxy = parse_or_search_proxy(proxy) if proxy else None
58
+ self.urls = urls
59
+
60
+ async def ascrape_playwright(self, url: str) -> str:
61
+ """
62
+ Asynchronously scrape the content of a given URL using Playwright's async API.
63
+
64
+ Args:
65
+ url (str): The URL to scrape.
66
+
67
+ Returns:
68
+ str: The scraped HTML content or an error message if an exception occurs.
69
+
70
+ """
71
+ from playwright.async_api import async_playwright
72
+
73
+ logger.info("Starting scraping...")
74
+ results = ""
75
+ async with async_playwright() as p:
76
+ browser = await p.chromium.launch(
77
+ headless=self.headless, proxy=self.proxy, **self.browser_config
78
+ )
79
+ try:
80
+ page = await browser.new_page()
81
+ await page.goto(url)
82
+ results = await page.content() # Simply get the HTML content
83
+ logger.info("Content scraped")
84
+ except Exception as e:
85
+ results = f"Error: {e}"
86
+ await browser.close()
87
+ return results
88
+
89
+ def lazy_load(self) -> Iterator[Document]:
90
+ """
91
+ Lazily load text content from the provided URLs.
92
+
93
+ This method yields Documents one at a time as they're scraped,
94
+ instead of waiting to scrape all URLs before returning.
95
+
96
+ Yields:
97
+ Document: The scraped content encapsulated within a Document object.
98
+
99
+ """
100
+ scraping_fn = getattr(self, f"ascrape_{self.backend}")
101
+
102
+ for url in self.urls:
103
+ html_content = asyncio.run(scraping_fn(url))
104
+ metadata = {"source": url}
105
+ yield Document(page_content=html_content, metadata=metadata)
106
+
107
+ async def alazy_load(self) -> AsyncIterator[Document]:
108
+ """
109
+ Asynchronously load text content from the provided URLs.
110
+
111
+ This method leverages asyncio to initiate the scraping of all provided URLs
112
+ simultaneously. It improves performance by utilizing concurrent asynchronous
113
+ requests. Each Document is yielded as soon as its content is available,
114
+ encapsulating the scraped content.
115
+
116
+ Yields:
117
+ Document: A Document object containing the scraped content, along with its
118
+ source URL as metadata.
119
+ """
120
+ scraping_fn = getattr(self, f"ascrape_{self.backend}")
121
+
122
+ tasks = [scraping_fn(url) for url in self.urls]
123
+ results = await asyncio.gather(*tasks)
124
+ for url, content in zip(self.urls, results):
125
+ metadata = {"source": url}
126
+ yield Document(page_content=content, metadata=metadata)
@@ -5,6 +5,7 @@ __init__.py file for graphs folder
5
5
  from .abstract_graph import AbstractGraph
6
6
  from .base_graph import BaseGraph
7
7
  from .smart_scraper_graph import SmartScraperGraph
8
+ from .deep_scraper_graph import DeepScraperGraph
8
9
  from .speech_graph import SpeechGraph
9
10
  from .search_graph import SearchGraph
10
11
  from .script_creator_graph import ScriptCreatorGraph
@@ -0,0 +1,116 @@
1
+ """
2
+ DeepScraperGraph Module
3
+ """
4
+
5
+ from .base_graph import BaseGraph
6
+ from ..nodes import (
7
+ FetchNode,
8
+ SearchLinkNode,
9
+ ParseNode,
10
+ RAGNode,
11
+ GenerateAnswerNode
12
+ )
13
+ from .abstract_graph import AbstractGraph
14
+
15
+
16
+ class DeepScraperGraph(AbstractGraph):
17
+ """
18
+ [WIP]
19
+
20
+ DeepScraper is a scraping pipeline that automates the process of
21
+ extracting information from web pages
22
+ using a natural language model to interpret and answer prompts.
23
+
24
+ Unlike SmartScraper, DeepScraper can navigate to the links within the input webpage,
25
+ to fuflfil the task within the prompt.
26
+
27
+
28
+ Attributes:
29
+ prompt (str): The prompt for the graph.
30
+ source (str): The source of the graph.
31
+ config (dict): Configuration parameters for the graph.
32
+ llm_model: An instance of a language model client, configured for generating answers.
33
+ embedder_model: An instance of an embedding model client,
34
+ configured for generating embeddings.
35
+ verbose (bool): A flag indicating whether to show print statements during execution.
36
+ headless (bool): A flag indicating whether to run the graph in headless mode.
37
+ Args:
38
+ prompt (str): The prompt for the graph.
39
+ source (str): The source of the graph.
40
+ config (dict): Configuration parameters for the graph.
41
+ Example:
42
+ >>> deep_scraper = DeepScraperGraph(
43
+ ... "List me all the job titles and detailed job description.",
44
+ ... "https://www.google.com/about/careers/applications/jobs/results/?location=Bangalore%20India",
45
+ ... {"llm": {"model": "gpt-3.5-turbo"}}
46
+ ... )
47
+ >>> result = deep_scraper.run()
48
+ )
49
+ """
50
+
51
+ def __init__(self, prompt: str, source: str, config: dict):
52
+ super().__init__(prompt, config, source)
53
+
54
+ self.input_key = "url" if source.startswith("http") else "local_dir"
55
+
56
+ def _create_graph(self) -> BaseGraph:
57
+ """
58
+ Creates the graph of nodes representing the workflow for web scraping.
59
+ Returns:
60
+ BaseGraph: A graph instance representing the web scraping workflow.
61
+ """
62
+ fetch_node = FetchNode(
63
+ input="url | local_dir",
64
+ output=["doc", "link_urls", "img_urls"]
65
+ )
66
+ parse_node = ParseNode(
67
+ input="doc",
68
+ output=["parsed_doc"],
69
+ node_config={
70
+ "chunk_size": self.model_token
71
+ }
72
+ )
73
+ rag_node = RAGNode(
74
+ input="user_prompt & (parsed_doc | doc)",
75
+ output=["relevant_chunks"],
76
+ node_config={
77
+ "llm_model": self.llm_model,
78
+ "embedder_model": self.embedder_model
79
+ }
80
+ )
81
+ search_node = SearchLinkNode(
82
+ input="user_prompt & relevant_chunks",
83
+ output=["relevant_links"],
84
+ node_config={
85
+ "llm_model": self.llm_model,
86
+ "embedder_model": self.embedder_model
87
+ }
88
+ )
89
+
90
+ return BaseGraph(
91
+ nodes=[
92
+ fetch_node,
93
+ parse_node,
94
+ rag_node,
95
+ search_node
96
+ ],
97
+ edges=[
98
+ (fetch_node, parse_node),
99
+ (parse_node, rag_node),
100
+ (rag_node, search_node)
101
+
102
+ ],
103
+ entry_point=fetch_node
104
+ )
105
+
106
+ def run(self) -> str:
107
+ """
108
+ Executes the scraping process and returns the answer to the prompt.
109
+ Returns:
110
+ str: The answer to the prompt.
111
+ """
112
+
113
+ inputs = {"user_prompt": self.prompt, self.input_key: self.source}
114
+ self.final_state, self.execution_info = self.graph.execute(inputs)
115
+
116
+ return self.final_state.get("answer", "No answer found.")
@@ -2,7 +2,7 @@
2
2
  OmniSearchGraph Module
3
3
  """
4
4
 
5
- from copy import copy
5
+ from copy import deepcopy
6
6
 
7
7
  from .base_graph import BaseGraph
8
8
  from ..nodes import (
@@ -43,7 +43,7 @@ class OmniSearchGraph(AbstractGraph):
43
43
  def __init__(self, prompt: str, config: dict):
44
44
 
45
45
  self.max_results = config.get("max_results", 3)
46
- self.copy_config = copy(config)
46
+ self.copy_config = deepcopy(config)
47
47
 
48
48
  super().__init__(prompt, config)
49
49
 
@@ -2,7 +2,7 @@
2
2
  SearchGraph Module
3
3
  """
4
4
 
5
- from copy import copy
5
+ from copy import deepcopy
6
6
 
7
7
  from .base_graph import BaseGraph
8
8
  from ..nodes import (
@@ -42,7 +42,7 @@ class SearchGraph(AbstractGraph):
42
42
  def __init__(self, prompt: str, config: dict):
43
43
 
44
44
  self.max_results = config.get("max_results", 3)
45
- self.copy_config = copy(config)
45
+ self.copy_config = deepcopy(config)
46
46
 
47
47
  super().__init__(prompt, config)
48
48
 
@@ -111,4 +111,4 @@ class SmartScraperGraph(AbstractGraph):
111
111
  inputs = {"user_prompt": self.prompt, self.input_key: self.source}
112
112
  self.final_state, self.execution_info = self.graph.execute(inputs)
113
113
 
114
- return self.final_state.get("answer", "No answer found.")
114
+ return self.final_state.get("answer", "No answer found.")
@@ -19,5 +19,4 @@ from .generate_answer_csv_node import GenerateAnswerCSVNode
19
19
  from .generate_answer_pdf_node import GenerateAnswerPDFNode
20
20
  from .graph_iterator_node import GraphIteratorNode
21
21
  from .merge_answers_node import MergeAnswersNode
22
- from .generate_answer_omni_node import GenerateAnswerOmniNode
23
- from .search_node_with_context import SearchLinksWithContext
22
+ from .generate_answer_omni_node import GenerateAnswerOmniNode
@@ -162,5 +162,4 @@ class FetchNode(BaseNode):
162
162
  ]
163
163
 
164
164
  state.update({self.output[0]: compressed_document, self.output[1]: link_urls, self.output[2]: image_urls})
165
-
166
165
  return state
@@ -38,7 +38,7 @@ class GenerateAnswerNode(BaseNode):
38
38
  super().__init__(node_name, "node", input, output, 2, node_config)
39
39
 
40
40
  self.llm_model = node_config["llm_model"]
41
- self.verbose = True if node_config is None else node_config.get(
41
+ self.verbose = False if node_config is None else node_config.get(
42
42
  "verbose", False)
43
43
 
44
44
  def execute(self, state: dict) -> dict:
@@ -4,6 +4,7 @@ MergeAnswersNode Module
4
4
 
5
5
  # Imports from standard library
6
6
  from typing import List, Optional
7
+ from tqdm import tqdm
7
8
 
8
9
  # Imports from Langchain
9
10
  from langchain.prompts import PromptTemplate
@@ -38,8 +39,7 @@ class MergeAnswersNode(BaseNode):
38
39
 
39
40
  def execute(self, state: dict) -> dict:
40
41
  """
41
- Executes the node's logic to merge the answers from multiple graph instances into a
42
- single answer.
42
+ Executes the node's logic to merge the answers from multiple graph instances into a single answer.
43
43
 
44
44
  Args:
45
45
  state (dict): The current state of the graph. The input keys will be used
@@ -35,15 +35,12 @@ class RobotsNode(BaseNode):
35
35
  """
36
36
 
37
37
  def __init__(self, input: str, output: List[str], node_config: Optional[dict]=None,
38
-
39
38
  node_name: str = "Robots"):
40
39
  super().__init__(node_name, "node", input, output, 1)
41
40
 
42
41
  self.llm_model = node_config["llm_model"]
43
-
44
- self.force_scraping = force_scraping
45
- self.verbose = True if node_config is None else node_config.get(
46
- "verbose", False)
42
+ self.force_scraping = False if node_config is None else node_config.get("force_scraping", False)
43
+ self.verbose = False if node_config is None else node_config.get("verbose", False)
47
44
 
48
45
  def execute(self, state: dict) -> dict:
49
46
  """
@@ -100,8 +97,7 @@ class RobotsNode(BaseNode):
100
97
  loader = AsyncChromiumLoader(f"{base_url}/robots.txt")
101
98
  document = loader.load()
102
99
  if "ollama" in self.llm_model.model_name:
103
- self.llm_model.model_name = self.llm_model.model_name.split(
104
- "/")[-1]
100
+ self.llm_model.model_name = self.llm_model.model_name.split("/")[-1]
105
101
  model = self.llm_model.model_name.split("/")[-1]
106
102
 
107
103
  else:
@@ -126,7 +122,7 @@ class RobotsNode(BaseNode):
126
122
  if "no" in is_scrapable:
127
123
  if self.verbose:
128
124
  print("\033[31m(Scraping this website is not allowed)\033[0m")
129
-
125
+
130
126
  if not self.force_scraping:
131
127
  raise ValueError(
132
128
  'The website you selected is not scrapable')