郭卫东 发表于 2024-11-18 18:57:40

Selenium+代理爬取需要模仿用户交互的网站

在一样平常爬虫采集网站的过程中,部分数据价值较高的网站,会限制访客的访问举动。这种时候发起通过登录的方式,获取目的网站的cookie,然后再使用cookie配合代理IP进行数据采集分析。本日我们就先容下如何使用Selenium库来爬取网页数据,特别是那些需要模仿用户交互的动态网页。
Selenium是一个自动化测试工具,它可以模仿用户在浏览器中的操作,比如点击按钮、填写表单等。与常用的BeautifulSoup、requests等爬虫库不同,Selenium可以处理JavaScript动态加载的内容,因此对于那些需要模仿用户交互才气获取的数据,Selenium是一个非常合适的选择。
通过联合Selenium的各种功能,我们可以编写强盛的网络爬虫来爬取各种网站上的数据。但请注意,在进行网络爬虫时,务必遵守目的网站的robots.txt规定,并恭敬网站的数据抓取政策。另外,过于频仍的爬取大概会给网站带来负担,甚至触发反爬机制,因此发起在爬取数据的过程中做好反爬措施,比如这里我们以访问知乎为例,通过获取网站的cookie在配合使用代理IP进行采集。关于代理IP一直都是爬虫小搭档们询问的题目,网上代理虽然多,但是优质的却很少,这里推荐有优质代理需求的可以试试亿牛云代理,提供的方式不仅有传统的api模式,还有隧道转发,发起大家都试试隧道转发,使用简单,方便,节约许多的时间去研究爬虫反爬机制。
这里我们就使用Selenium通过添加隧道转发代理访问知乎为例给大家提供一个参考:
    import os
    import time
    import zipfile

    from selenium import webdriver
    from selenium.common.exceptions import TimeoutException
    from selenium.webdriver.common.by import By
    from selenium.webdriver.support import expected_conditions as EC
    from selenium.webdriver.support.ui import WebDriverWait


    class GenCookies(object):
      # 随机useragent
      USER_AGENT = open('useragents.txt').readlines()


      # 代理服务器(产品官网 www.16yun.cn)
      PROXY_HOST = 't.16yun.cn'#proxy or host
      PROXY_PORT = 31111# port
      PROXY_USER = 'USERNAME'# username
      PROXY_PASS = 'PASSWORD'# password

      @classmethod
      def get_chromedriver(cls, use_proxy=False, user_agent=None):
            manifest_json = """
            {
                "version": "1.0.0",
                "manifest_version": 2,
                "name": "Chrome Proxy",
                "permissions": [
                  "proxy",
                  "tabs",
                  "unlimitedStorage",
                  "storage",
                  "<all_urls>",
                  "webRequest",
                  "webRequestBlocking"
                ],
                "background": {
                  "scripts": ["background.js"]
                },
                "minimum_chrome_version":"22.0.0"
            }
            """

            background_js = """
            var config = {
                  mode: "fixed_servers",
                  rules: {
                  singleProxy: {
                        scheme: "http",
                        host: "%s",
                        port: parseInt(%s)
                  },
                  bypassList: ["localhost"]
                  }
                };

            chrome.proxy.settings.set({value: config, scope: "regular"}, function() {});

            function callbackFn(details) {
                return {
                  authCredentials: {
                        username: "%s",
                        password: "%s"
                  }
                };
            }

            chrome.webRequest.onAuthRequired.addListener(
                        callbackFn,
                        {urls: ["<all_urls>"]},
                        ['blocking']
            );
            """ % (cls.PROXY_HOST, cls.PROXY_PORT, cls.PROXY_USER, cls.PROXY_PASS)
            path = os.path.dirname(os.path.abspath(__file__))
            chrome_options = webdriver.ChromeOptions()

            # 关闭webdriver的一些标志
            # chrome_options.add_experimental_option('excludeSwitches', ['enable-automation'])      


            if use_proxy:
                pluginfile = 'proxy_auth_plugin.zip'

                with zipfile.ZipFile(pluginfile, 'w') as zp:
                  zp.writestr("manifest.json", manifest_json)
                  zp.writestr("background.js", background_js)
                chrome_options.add_extension(pluginfile)
            if user_agent:
                chrome_options.add_argument('--user-agent=%s' % user_agent)
            driver = webdriver.Chrome(
                os.path.join(path, 'chromedriver'),
                chrome_options=chrome_options)

            # 修改webdriver get属性
            # script = '''
            # Object.defineProperty(navigator, 'webdriver', {
            # get: () => undefined
            # })
            # '''
            # driver.execute_cdp_cmd("Page.addScriptToEvaluateOnNewDocument", {"source": script})

            return driver

      def __init__(self, username, password):      
            # 登录example网站
            self.url = 'https://passport.example.cn/signin/login?entry=example&r=https://m.example.cn/'
            self.browser = self.get_chromedriver(use_proxy=True, user_agent=self.USER_AGENT)
            self.wait = WebDriverWait(self.browser, 20)
            self.username = username
            self.password = password

      def open(self):
            """
            打开网页输入用户名密码并点击
            :return: None
            """
            self.browser.delete_all_cookies()
            self.browser.get(self.url)
            username = self.wait.until(EC.presence_of_element_located((By.ID, 'loginName')))
            password = self.wait.until(EC.presence_of_element_located((By.ID, 'loginPassword')))
            submit = self.wait.until(EC.element_to_be_clickable((By.ID, 'loginAction')))
            username.send_keys(self.username)
            password.send_keys(self.password)
            time.sleep(1)
            submit.click()

      def password_error(self):
            """
            判断是否密码错误
            :return:
            """
            try:
                return WebDriverWait(self.browser, 5).until(
                  EC.text_to_be_present_in_element((By.ID, 'errorMsg'), '用户名或密码错误'))
            except TimeoutException:
                return False

      def get_cookies(self):
            """
            获取Cookies
            :return:
            """
            return self.browser.get_cookies()

      def main(self):
            """
            入口
            :return:
            """
            self.open()
            if self.password_error():
                return {
                  'status': 2,
                  'content': '用户名或密码错误'
                }            

            cookies = self.get_cookies()
            return {
                'status': 1,
                'content': cookies
            }


    if __name__ == '__main__':
      result = GenCookies(
            username='180000000',
            password='16yun',
      ).main()
      print(result)


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: Selenium+代理爬取需要模仿用户交互的网站