Package: botasaurus
🤖 Botasaurus 🤖The All in One Framework to build Awesome Scrapers.The web has evolved. Finally, web scraping has too.In a nutshellBotasaurus is an all-in-one web scraping framework that enables you to build awesome scrapers in less time. It solves the key pain points that we, as developers, face when scraping the modern web.Our mission is to make creating awesome scrapers easy for everyone.FeaturesBotasaurus is built for creating awesome scrapers. It comes fully baked, with batteries included. Here is a list of things it can do that no other web scraping framework can:Most Stealthiest Framework LITERALLY: Based on the benchmarks, which we encourage you to readhere, our framework stands as the most stealthy in both the JS and Python universes. It is more stealthy than the popular Python libraryundetected-chromedriverand the well-known JavaScript librarypuppeteer-stealth. Botasaurus can easily visit websites likehttps://nowsecure.nl/. With Botasaurus, you don't need to waste time finding ways to unblock a website. For usage,see this FAQ.Access Cloudflare Websites with Simple HTTP Requests:We can access Cloudflare-protected pages using simple HTTP requests. Saving you both time and money spent on proxies. For usage,see this FAQ.SSL Support for Authenticated Proxy:We are the first and only Python Web Scraping Framework as of writing to offer SSL support for authenticated proxies. No other browser automation libraries be it seleniumwire, puppeteer, playwright offers this important web scraping feature, this feautre enables you to easily access Cloudflare protected websites when using authenticated proxies, which would otherwise be blocked if you used only the bare authenticated proxy.Use Any Chrome Extension with Just 1 Line of Code:Easily integrate any Chrome extension, be it a Captcha Solving Extension, Adblocker, or any other from the Chrome Web Store, with justone line of code.. Say Sayonara, to the manual process of downloading, unzipping, configuring, and loading extensions.Sitemap Support:With justone line of code, you can get all links for a website.Data Cleaners:Make your scrapers robust by cleaning data with expert created data cleaners.Debuggability:When a crash occurs due to an incorrect selector, etc., Botasaurus pauses the browser instead of closing it, facilitating painless on-the-spot debugging.Caching:Botasaurus allows you to cache web scraping results, ensuring lightning-fast performance on subsequent scrapes.Easy Configuration:Easily save hours of Development Time with easy parallelization, profile, and proxy configuration. We make asynchronous, parallel scraping a child's play.Build Robust Scrapers:Easily configure retry on exceptions to ensure no errors comes in between you and the dataTime-Saving Selenium Shortcuts:Botasaurus comes with numerous Selenium shortcuts to make web scraping incredibly easy.🚀 Getting Started with BotasaurusWelcome to Botasaurus! Let’s dive right in with a straightforward example to understand how it works.In this tutorial, we will go through the steps to scrape the heading text fromhttps://www.omkar.cloud/.Step 1: Install BotasaurusFirst things first, you need to install Botasaurus. Run the following command in your terminal:python-mpipinstallbotasaurusStep 2: Set Up Your Botasaurus ProjectNext, let’s set up the project:Create a directory for your Botasaurus project and navigate into it:mkdirmy-botasaurus-projectcdmy-botasaurus-project
code.# This will open the project in VSCode if you have it installedStep 3: Write the Scraping CodeNow, create a Python script namedmain.pyin your project directory and insert the following code:frombotasaurusimport*@browserdefscrape_heading_task(driver:AntiDetectDriver,data):# Navigate to the Omkar Cloud websitedriver.get("https://www.omkar.cloud/")# Retrieve the heading element's textheading=driver.text("h1")# Save the data as a JSON file in output/scrape_heading_task.jsonreturn{"heading":heading}if__name__=="__main__":# Initiate the web scraping taskscrape_heading_task()Let’s understand this code:We define a custom scraping task,scrape_heading_task, decorated with@browser:@browserdefscrape_heading_task(driver:AntiDetectDriver,data):Botasaurus automatically provides an Anti Detection Selenium driver to our function:defscrape_heading_task(driver:AntiDetectDriver,data):Inside the function, we:Navigate to Omkar CloudExtract the heading textReturn the data to be automatically saved asscrape_heading_task.jsonby Botasaurus:driver.get("https://www.omkar.cloud/")heading=driver.text("h1")return{"heading":heading}Finally, we initiate the scraping task:if__name__=="__main__":scrape_heading_task()Step 4: Run the Scraping TaskTime to run your bot:pythonmain.pyAfter executing the script, it will:Launch Google ChromeNavigate toomkar.cloudExtract the heading textSave it automatically asoutput/scrape_heading_task.json.Now, let’s explore another way to scrape the heading using therequestmodule. Replace the previous code inmain.pywith the following:frombotasaurusimport*@requestdefscrape_heading_task(request:AntiDetectRequests,data):# Navigate to the Omkar Cloud websitesoup=request.bs4("https://www.omkar.cloud/")# Retrieve the heading element's textheading=soup.find('h1').get_text()# Save the data as a JSON file in output/scrape_heading_task.jsonreturn{"heading":heading}if__name__=="__main__":# Initiate the web scraping taskscrape_heading_task()In this code:We are using the BeautifulSoup (bs4) module to parse and scrape the heading.Therequestobject provided is not a standard Python request object but an Anti Detect request object, which also preserves cookies.Step 5: Run the Scraping Task (Using Anti Detect Requests)Finally, run the bot again:pythonmain.pyThis time, you will observe the same result as before, but instead of using Anti Detect Selenium, we are utilizing the Anti Detect request module.Note: If you don't have Python installed, then you can run Botasaurus in Gitpod, a browser-based development environment, by followingthis section.💡 Understanding BotasaurusLet's learn about the features of Botasaurus that assist you in web scraping and automation.Could you show me an example where you access Cloudflare Protected Website?Sure, Run the following Python code to access G2.com, a website protected by Cloudflare:frombotasaurusimport*@browser()defscrape_heading_task(driver:AntiDetectDriver,data):driver.google_get("https://www.g2.com/products/github/reviews")heading=driver.text('h1')print(heading)returnheadingscrape_heading_task()After running this script, you'll notice that the G2 page opens successfully, and the code prints the page's heading.How to Scrape Multiple Data Points/Links?To scrape multiple data points or links, define thedatavariable and provide a list of items to be scraped:@browser(data=["https://www.omkar.cloud/","https://www.omkar.cloud/blog/","https://stackoverflow.com/"])defscrape_heading_task(driver:AntiDetectDriver,data):# ...Botasaurus will launch a new browser instance for each item in the list and merge and store the results inscrape_heading_task.jsonat the end of the scraping.Please note that thedataparameter can also handle items such as dictionaries.For instance, if you're automating the sign-up process for bot accounts on a website, you can pass dictionaries to it like so:@browser(data=[{"name":"Mahendra Singh Dhoni",...},{"name":"Virender Sehwag",...}])defscrape_heading_task(driver:AntiDetectDriver,data:dict):# ...How to Scrape in Parallel?To scrape data in parallel, set theparalleloption in the browser decorator:@browser(parallel=3,data=["https://www.omkar.cloud/",...])defscrape_heading_task(driver:AntiDetectDriver,data):# ...How to know how many scrapers to run parallely?To determine the optimal number of parallel scrapers, pass thebt.calc_max_parallel_browsersfunction, which calculates the maximum number of browsers that can be run in parallel based on the available RAM:@browser(parallel=bt.calc_max_parallel_browsers,data=["https://www.omkar.cloud/",...])defscrape_heading_task(driver:AntiDetectDriver,data):# ...Example: If you have 5.8 GB of free RAM,bt.calc_max_parallel_browserswould return 10, indicating you can run up to 10 browsers in parallel.How to Cache the Web Scraping Results?To cache web scraping results and avoid re-scraping the same data, setcache=Truein the decorator:@browser(cache=True,data=["https://www.omkar.cloud/",...])defscrape_heading_task(driver:AntiDetectDriver,data):# ...How Botasaurus helps me in debugging?Botasaurus enhances the debugging experience by pausing the browser instead of closing it when an error occurs. This allows you to inspect the page and understand what went wrong, which can be especially helpful in debugging and removing the hassle of reproducing edge cases.Botasaurus also plays a beep sound to alert you when an error occurs.How to Block Resources like CSS, Images, and Fonts to Save Bandwidth?Blocking resources such as CSS, images, and fonts can significantly speed up your web scraping tasks, reduce bandwidth usage, and save money spent on proxies.For example, a page that originally takes 4 seconds and 12 MB's to load might only take one second and 100 KB to load after css, images, etc have been blocked.To block images, simply use theblock_resourcesparameter. For example:@browser(block_resources=True)# Blocks ['.css', '.jpg', '.jpeg', '.png', '.svg', '.gif', '.woff', '.pdf', '.zip']defscrape_heading_task(driver:AntiDetectDriver,data):driver.get("https://www.omkar.cloud/")driver.prompt()scrape_heading_task()If you wish to block only images and fonts, while allowing CSS files, you can setblock_imageslike this:@browser(block_images=True)# Blocks ['.jpg', '.jpeg', '.png', '.svg', '.gif', '.woff', '.pdf', '.zip']defscrape_heading_task(driver:AntiDetectDriver,data):driver.get("https://www.omkar.cloud/")driver.prompt()scrape_heading_task()To block a specific set of resources, such as only JavaScript, CSS, fonts, etc., specify them in the following manner:@browser(block_resources=['.js','.css','.jpg','.jpeg','.png','.svg','.gif','.woff','.pdf','.zip'])defscrape_heading_task(driver:AntiDetectDriver,data):driver.get("https://www.omkar.cloud/")driver.prompt()scrape_heading_task()How to Configure UserAgent, Proxy, Chrome Profile, Headless, etc.?To configure various settings such as UserAgent, Proxy, Chrome Profile, and headless mode, you can specify them in the decorator as shown below:frombotasaurusimport*@browser(headless=True,profile='my-profile',#   proxy="http://your_proxy_address:your_proxy_port", TODO: Replace with your own proxyuser_agent=bt.UserAgent.user_agent_106)defscrape_heading_task(driver:AntiDetectDriver,data):driver.get("https://www.omkar.cloud/")driver.prompt()scrape_heading_task()You can also pass additional parameters when calling the scraping function, as demonstrated below:@browser()defscrape_heading_task(driver:AntiDetectDriver,data):# ...data="https://www.omkar.cloud/"scrape_heading_task(data,headless=True,profile='my-profile',proxy="http://your_proxy_address:your_proxy_port",user_agent=bt.UserAgent.user_agent_106)Furthermore, it's possible to define functions that dynamically set these parameters based on the data item. For instance, to set the profile dynamically according to the data item, you can use the following approach:@browser(profile=lambdadata:data["profile"],headless=True,proxy="http://your_proxy_address:your_proxy_port",user_agent=bt.UserAgent.user_agent_106)defscrape_heading_task(driver:AntiDetectDriver,data):# ...data={"link":"https://www.omkar.cloud/","profile":"my-profile"}scrape_heading_task(data)Additionally, if you need to pass metadata that is common across all data items, such as an API Key, you can do so by adding it as ametadataparameter. For example:@browser()defscrape_heading_task(driver:AntiDetectDriver,data,metadata):print("metadata:",metadata)print("data:",data)data={"link":"https://www.omkar.cloud/","profile":"my-profile"}scrape_heading_task(data,metadata={"api_key":"BDEC26..."})Do you support SSL for Authenticated Proxies?Yes, we are the first Python Library to support SSL for authenticated proxies. Proxy providers like BrightData, IPRoyal, and others typically provide authenticated proxies in the format "http://username:password@proxy-provider-domain:port". For example, "http://greyninja:awesomepassword@geo.iproyal.com:12321".However, if you use an authenticated proxy with a library like seleniumwire to scrape a Cloudflare protected website like G2.com, you will surely be blocked because you are using a non-SSL connection.To verify this, run the following code:First, install the necessary packages:python-mpipinstallselenium_wirechromedriver_autoinstaller_fixThen, execute this Python script:fromseleniumwireimportwebdriverfromchromedriver_autoinstaller_fiximportinstall# Define the proxyproxy_options={'proxy':{'http':'http://username:password@proxy-provider-domain:port',# TODO: Replace with your own proxy'https':'http://username:password@proxy-provider-domain:port',# TODO: Replace with your own proxy}}# Install and set up the driverdriver_path=install()driver=webdriver.Chrome(driver_path,seleniumwire_options=proxy_options)# Navigate to the desired URLlink='https://www.g2.com/products/github/reviews'driver.get("https://www.google.com/")driver.execute_script(f'window.location.href = "{link}"')# Prompt for user inputinput("Press Enter to exit...")# Clean updriver.quit()You will definitely encounter a block by Cloudflare:However, using proxies with Botasaurus prevents this issue. See the difference by running the following code:frombotasaurusimport*@browser(proxy="http://username:password@proxy-provider-domain:port")# TODO: Replace with your own proxydefscrape_heading_task(driver:AntiDetectDriver,data):driver.google_get("https://www.g2.com/products/github/reviews")driver.prompt()scrape_heading_task()Result:NOTE: To run the code above, you will need Node.js installed.How to Access Cloudflare-Protected Websites Using Simple HTTP Requests?We can access Cloudflare-protected pages using simple HTTP requests.All you need to do is specify theuse_stealthoption.Sounds too good to be true? Run the following code to see it in action:frombotasaurusimport*@request(use_stealth=True)defscrape_heading_task(request:AntiDetectRequests,data):response=request.get('https://www.g2.com/products/github/reviews')print(response.status_code)returnresponse.textscrape_heading_task()Can you access websites protected by Cloudflare JS Challenge?Yes, we can. Let's learn about various challenges and the best ways to solve them.Connection ChallengeThis is the most popular challenge and requires making a browser-like connection with appropriate headers to the target website. It's commonly used to protect:Product PagesBlog PagesSearch Result PagesExample Page:https://www.g2.com/products/github/reviewsWhat Does Not Work?Usingcloudscraperlibrary fails because, while it sends browser-like user agents and headers, it does not establish a browser-like connection, leading to detection.What Works?Use the stealth request mode and visit via Google (default behavior). [Recommended]frombotasaurusimport*@request(use_stealth=True)defscrape_heading_task(request:AntiDetectRequests,data):response=request.get('https://www.g2.com/products/github/reviews')print(response.status_code)returnresponse.textscrape_heading_task()Use a real Chrome browser with Selenium and visit via Google. Example Code:frombotasaurusimport*@browser()defscrape_heading_task(driver:AntiDetectDriver,data):driver.google_get("https://www.g2.com/products/github/reviews")driver.prompt()heading=driver.text('h1')returnheadingscrape_heading_task()JS ChallengeThis challenge requires performing JS computations that differentiates a Chrome controlled by Selenium/Puppeteer/Playwright from a real Chrome.It's commonly used to protect:Login/Sign Up pagesSign Up FlowsExample Pages:https://nowsecure.nl/What Does Not Work?Bareseleniumandpuppeteerdefinitely do not work due to a lot of automation noise.undetected-chromedriverandpuppeteer-stealthalso fail to access sites protected by JS Challenge likehttps://nowsecure.nl/.What Works?The Stealth Browser can easily solve JS Challenges. See the truth for yourself by running this code:frombotasaurusimport*frombotasaurus.create_stealth_driverimportcreate_stealth_driver@browser(create_driver=create_stealth_driver(start_url="https://nowsecure.nl/",),)defscrape_heading_task(driver:AntiDetectDriver,data):driver.prompt()heading=driver.text('h1')returnheadingscrape_heading_task()JS with Captcha ChallengeThis challenge involves JS computations plus solving a Captcha. It's used to protect pages which are rarely but sometimes visited by humans, like:5th Page of G2 Reviews8th Page of Google Search ResultsExample Page:https://www.g2.com/products/github/reviews.html?page=5&product_id=githubWhat Does Not Work?Again, tools likeselenium,puppeteer,undetected-chromedriver, andpuppeteer-stealthfail.What Works?The Stealth Browser can easily solve these challenges. See it in action by running this code:frombotasaurusimport*frombotasaurus.create_stealth_driverimportcreate_stealth_driver@browser(create_driver=create_stealth_driver(start_url="https://www.g2.com/products/github/reviews.html?page=5&product_id=github",),)defscrape_heading_task(driver:AntiDetectDriver,data):driver.prompt()heading=driver.text('h1')returnheadingscrape_heading_task()Notes:In stealth browser mode, we default to an 8-second wait before connecting to the browser via Selenium because connecting too early gets us detected. You can customize the wait time by using thewaitargument.frombotasaurusimport*frombotasaurus.create_stealth_driverimportcreate_stealth_driver@browser(create_driver=create_stealth_driver(start_url="https://nowsecure.nl/",wait=4,# Waits for 4 seconds before connecting to browser),)defscrape_heading_task(driver:AntiDetectDriver,data):driver.prompt()heading=driver.text('h1')returnheadingscrape_heading_task()Here are some recommendations for wait times:For active development with fast internet, set the wait time to4 seconds. You most likely have a fast internet connection, so set the wait time to4 secondswhen developing your Bot.If during development you have a slow internet connection, then stick with the default8 seconds.If you get detected, try changing your IP. Let me share with you  Thefastest,simplest, and best of all, thefreeway to change your IP:Connect your PC to the Internet via a Mobile Hotspot.Toggle airplane mode off and on on your mobile device.This will assign you a new IP address.Turn the hotspot back on.Voila, you have a new, high-quality mobile IP for free!If you are automating Cloudflare Websites with JS Challenges likehttps://nowsecure.nl/, then you must pass start_url to solve them like this:frombotasaurusimport*frombotasaurus.create_stealth_driverimportcreate_stealth_driver@browser(create_driver=create_stealth_driver(start_url="https://nowsecure.nl/",# Must for Websites Protected by Cloudflare JS Challenge),)However, if you are automating websites not protected by Cloudflare or protected by Cloudflare Connection Challenge, then you may passNoneto start_url. With this, we will also not perform a wait before connecting to Chrome, saving you time.frombotasaurusimport*frombotasaurus.create_stealth_driverimportcreate_stealth_driver@browser(create_driver=create_stealth_driver(start_url=None,# Recommended for Websites not protected by Cloudflare or protected by Cloudflare Connection Challenge),)Anti Detection Systems can detect fake randomly generated user agents. So, if you are getting detected, especially on Ubuntu with Cloudflare JS with Captcha Challenge, we recommend using your real user agent and window size, not a randomly generated one. Here's how you can do it:frombotasaurusimport*frombotasaurus.create_stealth_driverimportcreate_stealth_driver@browser(user_agent=bt.UserAgent.REAL,window_size=bt.WindowSize.REAL,create_driver=create_stealth_driver(start_url="https://nowsecure.nl/",),)defscrape_heading_task(driver:AntiDetectDriver,data):driver.prompt()heading=driver.text('h1')returnheadingscrape_heading_task()If you are doing web scraping of publicly available data, then the above code is good and recommended to be used. However, if you are creating multiple accounts, then we don't recommend using the above code because the website may use tools likefingerprintto capture fingerprints and uniquely identify that bots are creating multiple accounts.We expect to access Cloudflare websites 9 out of 10 times. However, in some cases, they do detect us for reasons like IP blacklisting. In such cases, you can use the following code snippet to make your scraper more robust:frombotasaurusimport*frombotasaurus.create_stealth_driverimportcreate_stealth_driverdefget_start_url(data):returndata@browser(# proxy="http://username:password@proxy-domain:12321" # optionally use proxy# user_agent=bt.UserAgent.REAL, # Optionally use REAL User Agent# window_size=bt.WindowSize.REAL, # Optionally use REAL Window Sizemax_retry=5,create_driver=create_stealth_driver(start_url=get_start_url,raise_exception=True,),)defscrape_heading_task(driver:AntiDetectDriver,data):driver.prompt()heading=driver.text('h1')returnheadingscrape_heading_task(["https://nowsecure.nl/","https://steamdb.info/sub/363669/apps"])The above code makes the scraper more robust by raising an exception when detected and retrying up to 5 times to visit the website.How to Solve Captchas in Web Scraping?Facing captchas is really common and annoying hurdle in web scraping. Fortunately, CapSolver can be used to automatically solve captchas, saving both time and effort. Here's how you can use it:frombotasaurusimport*fromcapsolver_extension_pythonimportCapsolver@browser(extensions=[Capsolver(api_key="CAP-MY_KEY")],# Replace "CAP-MY_KEY" with your actual CapSolver Key)defsolve_captcha(driver:AntiDetectDriver,data):driver.get("https://recaptcha-demo.appspot.com/recaptcha-v2-checkbox.php")driver.prompt()solve_captcha()To solve captcha's with CapSolver, you will need Capsolver API Key. If you do not have a CapSolver API Key, follow the instructionshereto create a CapSolver account and obtain one.How to Use Chrome Extensions?Botasaurus allows the use of ANY Chrome Extension with just 1 Line of Code. Below is an example that uses the AdBlocker Chrome Extension:frombotasaurusimport*fromchrome_extension_pythonimportExtension@browser(extensions=[Extension("https://chromewebstore.google.com/detail/adblock-%E2%80%94-best-ad-blocker/gighmmpiobklfepjocnamgkkbiglidom")],# Simply pass the Extension Link)defopen_chrome(driver:AntiDetectDriver,data):driver.prompt()open_chrome()Also, In some cases an extension requires additional configuration like API keys or credentials, for that you can create a Custom Extension. Learn how to create and configure Custom Extensionhere.I want to Scrape a large number of Links, a new selenium driver is getting created for each new link, this increases the time to scrape data. How can I reuse Drivers?Utilize thereuse_driveroption to reuse drivers, reducing the time required for data scraping:@browser(reuse_driver=True)defscrape_heading_task(driver:AntiDetectDriver,data):# ...How to Extract Links from a Sitemap?In web scraping, it is a common use case to scrape product pages, blogs, etc. But before scraping these pages, you need to get the links to these pages.Many developers unnecessarily increase their work by writing code to visit each page one by one and scrape links, which they could have easily by just looking at the Sitemap.The Botasaurus Sitemap Module makes this process easy as cake by allowing you to get all links or sitemaps using:The homepage URL (e.g.,https://www.omkar.cloud/)A direct sitemap link (e.g.,https://www.omkar.cloud/sitemap.xml)A.gzcompressed sitemap (e.g.,https://www.g2.com/sitemaps/sitemap_index.xml.gz)For example, if you're an Angel Investor seeking innovative tech startups, G2 is an ideal platform where companies showcase their products. You can run the following code to fetch over 160K+ product links from G2:frombotasaurusimport*frombotasaurus.sitemapimportSitemap,Filters,Extractorslinks=(Sitemap("https://www.g2.com/sitemaps/sitemap_index.xml.gz").filter(Filters.first_segment_equals("products")).extract(Extractors.extract_link_upto_second_segment()).links())bt.write_temp_json(links)Output:Or, if you're in the mood for some reading and looking for good stories, the following code will get you over 1000+ stories frommoralstories26.com:frombotasaurusimport*frombotasaurus.sitemapimportSitemap,Filterssitemaps=(Sitemap("https://moralstories26.com/").filter(Filters.has_exactly_1_segment(),Filters.first_segment_not_equals(["about","privacy-policy","akbar-birbal","animal","education","fables","facts","family","famous-personalities","folktales","friendship","funny","heartbreaking","inspirational","life","love","management","motivational","mythology","nature","quotes","spiritual","uncategorized","zen"]),).links())bt.write_temp_json(sitemaps)Output:Before scraping a site, it's useful to identify the available sitemaps. This can be easily done with the following code:frombotasaurusimport*frombotasaurus.sitemapimportSitemapsitemaps=Sitemap("https://www.omkar.cloud/").sitemaps()bt.write_temp_json(sitemaps)Output:To ensure your scrapers run super fast, we cache the Sitemap, but you may want to periodically refresh the cache, which you can do as follows:frombotasaurusimport*frombotasaurus.sitemapimportSitemapfrombotasaurus.cacheimportCachesitemap=Sitemap(["https://moralstories26.com/post-sitemap.xml","https://moralstories26.com/post-sitemap2.xml",],cache=Cache.REFRESH,# Refresh the cache with up-to-date stories.)links=sitemap.links()bt.write_temp_json(links)In summary, the sitemap is an awesome module for easily extracting links you want for web scraping.Could you show me a practical example where all these Botasaurus Features Come Together to accomplish a typical web scraping project?Below is a practical example of how Botasaurus features come together in a typical web scraping project to scrape a list of links from a blog, and then visit each link to retrieve the article's heading and date:frombotasaurusimport*@browser(block_resources=True,cache=True,parallel=bt.calc_max_parallel_browsers,reuse_driver=True)defscrape_articles(driver:AntiDetectDriver,link):driver.get(link)heading=driver.text("h1")date=driver.text("time")return{"heading":heading,"date":date,"link":link,}@browser(block_resources=True,cache=True)defscrape_article_links(driver:AntiDetectDriver,data):# Visit the Omkar Cloud websitedriver.get("https://www.omkar.cloud/blog/")links=driver.links("h3 a")returnlinksif__name__=="__main__":# Launch the web scraping tasklinks=scrape_article_links()scrape_articles(links)How to Clean Data?Botasaurus provides a module namedclthat includes commonly used cleaning functions to save development time. Here are some of the most important ones:cl.selectWhatdocument.querySelectoris to js, is whatcl.selectis to json. This is the most used function in Botasaurus and is incredibly useful.This powerful function is popular for safely selecting data from nested JSON.Instead of using flaky code like this:frombotasaurusimportcldata={"person":{"data":{"name":"Omkar","age":21}},"data":{"friends":[{"name":"John","age":21},{"name":"Jane","age":21},{"name":"Bob","age":21}]}}name=data.get('person',{}).get('data',{}).get('name',None)ifname:name=name.upper()else:name=Noneprint(name)You can write it as:frombotasaurusimportcldata={"person":{"data":{"name":"Omkar","age":21}},"data":{"friends":[{"name":"John","age":21},{"name":"Jane","age":21},{"name":"Bob","age":21}]}}print(cl.select(data,'name',map_data=lambdax:x.upper()))cl.selectreturnsNoneif the key is not found, instead of throwing an error.frombotasaurusimportclprint(cl.select(data,'name'))# Omkarprint(cl.select(data,'friends',0,'name'))# Johnprint(cl.select(data,'friends',0,'non_existing_key'))# NoneYou can also usemap_datalike this:frombotasaurusimportclcl.select(data,'name',map_data=lambdax:x.upper())# OMKARAnd use default values like this:frombotasaurusimportclcl.select(None,'name',default="OMKAR")# OMKARcl.extract_numbersfrombotasaurusimportclprint(cl.extract_numbers("I can extract numbers with decimal like 4.5, or with comma like 1,000."))# [4.5, 1000]More Functionsfrombotasaurusimportclprint(cl.extract_links("I can extract links like https://www.omkar.cloud/ or https://www.omkar.cloud/blog/"))# ['https://www.omkar.cloud/', 'https://www.omkar.cloud/blog/']print(cl.rename_keys({"name":"Omkar","age":21},{"name":"full_name"}))# {"full_name": "Omkar", "age": 21}print(cl.sort_object_by_keys({"age":21,"name":"Omkar"},"name"))# {"name": "Omkar", "age": 21}print(cl.extract_from_dict([{"name":"John","age":21},{"name":"Jane","age":21},{"name":"Bob","age":21}],"name"))# ["John", "Jane", "Bob"]# ... And many moreHow to Read/Write JSON and CSV Files?Botasaurus provides convenient methods for reading and writing data:# Data to write to the filedata=[{"name":"John Doe","age":42},{"name":"Jane Smith","age":27},{"name":"Bob Johnson","age":35}]# Write the data to the file "data.json"bt.write_json(data,"data.json")# Read the contents of the file "data.json"print(bt.read_json("data.json"))# Write the data to the file "data.csv"bt.write_csv(data,"data.csv")# Read the contents of the file "data.csv"print(bt.read_csv("data.csv"))How Can I Pause the Scraper to Inspect Things While Developing?To pause the scraper and wait for user input before proceeding, usebt.prompt():bt.prompt()How Does AntiDetectDriver Facilitate Easier Web Scraping?AntiDetectDriver is a patched Version of Selenium that has been modified to avoid detection by bot protection services such as Cloudflare.It also includes a variety of helper functions that make web scraping tasks easier.You can learn about these methodshere.What Features Does @request Support, Similar to @browser?Similar to @browser, @request supports features likeasynchronous execution [Will Learn Later]parallel processingcachinguser-agent customizationproxies, etc.Below is an example that showcases these features:@request(parallel=40,cache=True,proxy="http://your_proxy_address:your_proxy_port",data=["https://www.omkar.cloud/",...])defscrape_heading_task(request:AntiDetectDriver,link):soup=request.bs4(link)heading=soup.find('h1').get_text()return{"heading":heading}I have an existing project into which I want to integrate the AntiDetectDriver/AntiDetectRequests.You can create an instance ofAntiDetectDriveras follows:driver=bt.create_driver()# ... Code for scrapingdriver.quit()You can create an instance ofAntiDetectRequestsas follows:anti_detect_request=bt.create_request()soup=anti_detect_request.bs4("https://www.omkar.cloud/")# ... Additional codeSign Up BotsSometimes, data is hidden behind an authentication wall, requiring you to sign up via email or Google to access it. Sign-up automation is designed for this use case; it assists in downloading reports, scraping account usage history, and more.Please note that it is important to use this functionality ethically and only for legitimate purposes. You can learn about ithereHow to Run Botasaurus in Docker?To run Botasaurus in Docker, use the Botasaurus Starter Template, which includes the necessary Dockerfile and Docker Compose configurations:git clone https://github.com/omkarcloud/botasaurus-starter my-botasaurus-project
cd my-botasaurus-project
docker-compose build && docker-compose upHow to Run Botasaurus in Gitpod?Botasaurus Starter Template comes with the necessary.gitpod.ymlto easily run it in Gitpod, a browser-based development environment. Set it up in just 5 minutes by following these steps:Open Botasaurus Starter Template, by visitingthis linkand sign up using your GitHub account.In the terminal, run the following command to start scraping:pythonmain.pyAdvanced FeaturesHow Do I Configure the Output of My Scraping Function in Botasaurus?To configure the output of your scraping function in Botasaurus, you can customize the behavior in several ways:Change Output Filename: Use theoutputparameter in the decorator to specify a custom filename for the output.@browser(output="my-output")defscrape_heading_task(driver:AntiDetectDriver,data):# Your scraping logic hereDisable Output: If you don't want any output to be saved, setoutputtoNone.@browser(output=None)defscrape_heading_task(driver:AntiDetectDriver,data):# Your scraping logic hereDynamically Write Output: To dynamically write output based on data and result, pass a function to theoutputparameter:defwrite_output(data,result):bt.write_json(result,'data')bt.write_csv(result,'data')@browser(output=write_output)defscrape_heading_task(driver:AntiDetectDriver,data):# Your scraping logic hereSave Outputs in Multiple Formats: Use theoutput_formatsparameter to save outputs in different formats like CSV and JSON.@browser(output_formats=[bt.Formats.CSV,bt.Formats.JSON])defscrape_heading_task(driver:AntiDetectDriver,data):# Your scraping logic hereThese options provide flexibility in how you handle the output of your scraping tasks with Botasaurus.How to Run Drivers Asynchronously from the Main Process?To execute drivers asynchronously, enable theasyncoption and use.get()when you're ready to collect the results:frombotasaurusimport*fromtimeimportsleep@browser(run_async=True,# Specify the Async option here)defscrape_heading(driver:AntiDetectDriver,data):print("Sleeping for 5 seconds.")sleep(5)print("Slept for 5 seconds.")return{}if__name__=="__main__":# Launch web scraping tasks asynchronouslyresult1=scrape_heading()# Launches asynchronouslyresult2=scrape_heading()# Launches asynchronouslyresult1.get()# Wait for the first resultresult2.get()# Wait for the second resultWith this method, function calls run concurrently. The output will indicate that both function calls are executing in parallel.How to Asynchronously Add Multiple Items and Get Results?Theasync_queuefeature allows you to perform web scraping tasks in asyncronously in a queue, without waiting for each task to complete before starting the next one. To gather your results, simply use the.get()method when all tasks are in the queue.Basic Example:frombotasaurusimport*fromtimeimportsleep@browser(async_queue=True)defscrape_data(driver:AntiDetectDriver,data):print("Starting a task.")sleep(1)# Simulate a delay, e.g., waiting for a page to loadprint("Task completed.")returndataif__name__=="__main__":# Start scraping tasks without waiting for each to finishasync_queue=scrape_data()# Initializes the queue# Add tasks to the queueasync_queue.put([1])async_queue.put(2)async_queue.put([3,4])# Retrieve results when readyresults=async_queue.get()# Expects to receive: [1, 2, 3, 4]Practical Application for Web Scraping:Here's how you could useasync_queueto scrape webpage titles while scrolling through a list of links:frombotasaurusimport*@browser(async_queue=True)defscrape_title(driver:AntiDetectDriver,link):driver.get(link)# Navigate to the linkreturndriver.title# Scrape the title of the webpage@browser()defscrape_all_titles(driver:AntiDetectDriver):# ... Your code to visit the initial page ...title_queue=scrape_title()# Initialize the asynchronous queuewhilenotend_of_page_detected(driver):# Replace with your end-of-list conditiontitle_queue.put(driver.links('a'))# Add each link to the queuedriver.scroll(".scrollable-element")returntitle_queue.get()# Get all the scraped titles at onceif__name__=="__main__":all_titles=scrape_all_titles()# Call the function to start the scraping processNote:Theasync_queuewill only invoke the scraping function for unique links, avoiding redundant operations and keeping the main function (scrape_all_titles) cleaner.I want to repeatedly call the scraping function without creating new Selenium drivers each time. How can I achieve this?Utilize thekeep_drivers_aliveoption to maintain active driver sessions. Remember to call.close()when you're finished to release resources:@browser(keep_drivers_alive=True,parallel=bt.calc_max_parallel_browsers,# Typically used with `keep_drivers_alive`reuse_driver=True,# Also commonly paired with `keep_drivers_alive`)defscrape_data(driver:AntiDetectDriver,data):# ... (Your scraping logic here)if__name__=="__main__":foriinrange(3):scrape_data()# After completing all scraping tasks, call .close() to close the drivers.scrape_data.close()How do I manage the Cache in Botasaurus?You can use The Cache Module in Botasaurus to easily manage cached data. Here's a simple example explaining its usage:frombotasaurusimport*frombotasaurus.cacheimportCache# Example scraping function@requestdefscrape_data(data):# Your scraping logic herereturn{"processed":data}# Sample data for scrapinginput_data={"key":"value"}# Adding data to the cacheCache.put(scrape_data,input_data,scrape_data(input_data))# Checking if data is in the cacheifCache.has(scrape_data,input_data):# Retrieving data from the cachecached_data=Cache.get(scrape_data,input_data)# Removing specific data from the cacheCache.remove(scrape_data,input_data)# Clearing the complete cache for the scrape_data functionCache.clear(scrape_data)Any Tips for Scraping Cloudflare-Protected Websites?Use stealth driverFor large-scale scraping, opt for Data Center Proxies over Residential as Residential Proxies are really expensive. Sometimes you will get blocked; so, use retries as demonstrated in the code below:frombotasaurusimport*frombotasaurus.create_stealth_driverimportcreate_stealth_driver@browser(create_driver=create_stealth_driver(start_url="https://nowsecure.nl/",),proxy="http://username:password@datacenter-proxy-domain:12321",max_retry=5,# A reliable default for most situations, will retry creating driver if detected.block_resources=True,# Enhances efficiency and cost-effectiveness)defscrape_heading_task(driver:AntiDetectDriver,data):heading=driver.text('h1')print(heading)returnheadingHow Do I Close All Running Chrome Instances When Developing with Botasaurus?While developing a scraper, you might need to interrupt the scraping process, often done by pressingCtrl + C. However, this action does not automatically close the Chrome browsers, which can cause your computer to hang due to resource overuse.To prevent your PC from hanging, you need to close all running Chrome instances.You can run following command to close all chromespython-mbotasaurus.closeExecuting above command will close all Chrome instances, thereby helping to prevent your PC from hanging.What feautres are Coming in Botasaurus 4?Botasaurus 4, which is currently in its beta phase, allows you to:A sms API to receive OTPs.Run bots in the cloud using a website UI and control their schedules, starting/stopping times, and view bot outputs in a web UI.Use Kubernetes to run thousands of bots in parallel.Schedule Scraping Tasks at specific times or intervalsWhatsapp/Email AlertsAn API to interface with Gmail and Outlook accounts.MySQL/PostgreSQL IntegrationAnd Many More :)Developers are actively using Botasaurus 4 in production environments and saving hours of Development Time. To get access to Botasaurus 4, pleasereach out to usand let us know which feature you would like to access.ConclusionBotasaurus is a powerful, flexible tool for web scraping.Its various settings allow you to tailor the scraping process to your specific needs, improving both efficiency and convenience. Whether you're dealing with multiple data points, requiring parallel processing, or need to cache results, Botasaurus provides the features to streamline your scraping tasks.❓ Need More Help or Have Additional Questions?For further help, ask your question in GitHub Discussions. We'll be happy to help you out.ThanksKudos to the Apify Team for creating thegot-scrapingandproxy-chainlibraries. The implementation of stealth Anti Detect Requests and SSL-based Proxy Authentication wouldn't have been possible without their groundbreaking work ongot-scrapingandproxy-chain.Shout out to zfcsoftware for developingpuppeteer-real-browser; it helped us in creating Botasaurus Anti Detected. Show your appreciation by subscribing to theirYouTube channel⚡.A special thanks to the Selenium team for creating Selenium, an invaluable tool in our toolkit.Thanks to Cloudflare, DataDome, Imperva, and all bot detectors. Had you not been there, we wouldn't be either 😅.Finally, a humongous thank you for choosing Botasaurus.Love It?Star It! ⭐Become one of our amazing stargazers by giving us a star ⭐ on GitHub!It's just one click, but it means the world to me.Disclaimer for Botasaurus ProjectBy using Botasaurus, you agree to comply with all applicable local and international laws related to data scraping, copyright, and privacy. The developers of Botasaurus are not responsible for any misuse of this software. It is the sole responsibility of the user to ensure adherence to all relevant laws regarding data scraping, copyright, and privacy, and to use Botasaurus in an ethical and legal manner.We take the concerns of the Botasaurus Project very seriously. For any inquiries or issues, please contact Chetan Jain atchetan@omkar.cloud. We will take prompt and necessary action in response to your emails.Made with ❤️ in Bharat 🇮🇳 - Vande Mataram