Python爬虫实战(保姆级登网页信息爬取教程)

news2024/12/28 13:15:51

此blog为爬虫实战教学,代码已附上,可以复制运行。若要直接看实战代码翻到博客后半部分。

本文使用selenium库进行爬虫,实现爬取数据操作,此库是通过模仿用户的操作进行对页面的处理。了解了这个思维模式,可以对代码进行进一步的理解。

selenium库的操作方式可以看之前写过的爬虫登录教学~还有如何找到网页上板块的xpath的步骤。Python爬虫实战(保姆级自动登录教程)


引:

在本篇博客中,实现了登录→搜索→设置→爬取的过程。

本文以中塑行情网站进行举例进行爬取数据,网站的地址为

https://quote.21cp.com/

有小伙伴可能会好奇,为什么我要写这样一个程序。当然是因为手动太麻烦啦。看下文的爬取思路就能看出来,其实爬虫在某些步骤上就是一个模拟手动点击的过程。

在写爬虫程序之前,要先理清思路,搞明白要做哪些步骤,先后顺序是什么,然后将每个步骤封装成函数,再一步步调试编写代码。


1、爬取思路

在公司中,需要爬取中塑行情网站上一些项目的历史价格。

可以看到爬取这些项目需要的信息有四个,分别是产品名称、关键字、起始时间和终止时间。当然,也不要忘记需要登录才能看到数据,因此,我们也需要用户名和密码进行登录。

添加图片注释,不超过 140 字(可选)

现有这样一个.xslx的表格文件,包含了查找需要的项目信息所需要的背景信息。

整理爬取的思路,首先就要从手动获取目标信息开始尝试。

添加图片注释,不超过 140 字(可选)

首先,我们登陆了行情网的首页,此时点击石化出厂价会发现看不了数据,因为我们没有登陆。说明需要登录才可以爬取数据。

添加图片注释,不超过 140 字(可选)

所以我们点击登录转到登录网页(后续我们选择直接获取登录页面的网址直接进行跳转,但也可以从首页用selenium点击)。

添加图片注释,不超过 140 字(可选)

我们推荐选择二维码登录(或者账号密码+验证码),二维码登录即在手机上先下载好app进行扫码,这样的话后续代码调试的时候不用一遍遍输入账号密码和验证码,更为便捷。

登录以后根据公司的要求,需要点击石化出价场这个按钮,

添加图片注释,不超过 140 字(可选)

添加图片注释,不超过 140 字(可选)

后面我们每一个项目的搜索起始页面都是它,所以我们也可以记下它的网站,到时候直接跳转,但如果从首页用selenium点击石化出厂价也是可以的。

添加图片注释,不超过 140 字(可选)

以第一个项目为例。

添加图片注释,不超过 140 字(可选)

首先 ,将关键字548r输入搜索框,然后再点击搜索按钮。

添加图片注释,不超过 140 字(可选)

然后,找到包含.xlsx表格中产品名称“镇海”的一栏,点击历史价格。

添加图片注释,不超过 140 字(可选)

可以看到显示折线图,但我们要获取的是数据,所以点击红框框出来的按钮。

然后,再日期范围中输入表格文件中标定的起始日期和终止日期,并点击查询。(输入前需要将原先默认填写好的日期删除,这是我曾经出错过的地方)

添加图片注释,不超过 140 字(可选)

翻到最底部可以看到不止一页,爬虫的时候要点击下一页,直到下一页的按钮不能被点击。

如果我们手动获取,我们需要一个个搜索,一个个输入日期并点击导出按钮,并在个人信息页上下载表格,太复杂了,但我们检查网页上的信息。

添加图片注释,不超过 140 字(可选)

右击点击检查,再点击下图所示的图标。

添加图片注释,不超过 140 字(可选)

添加图片注释,不超过 140 字(可选)

可以看到表格中的数据都能被爬取到,且通过这种方式可以获取网页部件的Xpath(手把手获取Xpath教学可以看之前写过的爬虫登录教学博客Python爬虫实战(保姆级自动登录教程))

此时,这个项目信息就获取完了,若要搜索下一个项目信息,则点击左边栏目中的“石化出厂价”,再次回到如下页面。

添加图片注释,不超过 140 字(可选)


2、代码编写

  • __init__:这是类的构造函数,用于初始化实例变量。

def __init__(self):    self.status = 0         # 状态,表示如今进行到何种程度    self.login_method = 1   # {0:模拟登录,1:Cookie登录}自行选择登录方式    chrome_options = Options()    chrome_options.add_argument("start-maximized")  # 启动时最大化窗口    self.driver = webdriver.Chrome(options=chrome_options)
    • self.status

      :用于跟踪程序的当前状态。

    • self.login_method

      :选择登录方式,0代表模拟登录,1代表使用Cookie登录。

    • chrome_options

      :设置Chrome浏览器选项,如启动时最大化窗口。

    • self.driver

      :初始化一个Chrome WebDriver实例。

  • set_cookie:使用扫码登录获取cookie,并保存到本地文件。

    def set_cookie(self):    self.driver.get(login_url)    sleep(2)  # 等待页面加载    while self.driver.title.find('账号登录-中塑在线-21世纪塑料行业门户') == -1:        sleep(1)    print('###请扫码登录###')    # 最大化浏览器窗口    self.driver.maximize_window()    sleep(2)  # 等待页面加载    while self.driver.title == '账号登录-中塑在线-21世纪塑料行业门户':        sleep(1)    print("###扫码成功###")    cookies = self.driver.get_cookies()    with open("cookies.pkl", "wb") as f:        pickle.dump(cookies, f)    print("###Cookie保存成功###")    self.driver.get(target_url)
    • 打开登录页面,等待页面加载,并提示用户扫码登录。

    • 最大化浏览器窗口,等待扫码成功后获取cookie。

    • 将获取到的cookie保存到本地文件cookies.pkl

  • get_cookie:从本地文件加载cookie并应用到当前浏览器会话。c尝试从cookies.pkl文件中加载cookie,并添加到当前的WebDriver会话中。

  • login:根据self.login_method的值选择登录方式。

    def login(self):    if self.login_method == 0:        self.driver.get(login_url)        print('###开始登录###')    elif self.login_method == 1:        self.set_cookie()
    • 如果是模拟登录(self.login_method == 0),则直接访问登录页面。

    • 如果是使用Cookie登录(self.login_method == 1),则调用set_cookie方法。

  • enter_concert:打开浏览器,进入中塑在线网站,并进行登录。

    def enter_concert(self):    """打开浏览器"""    print('###打开浏览器,进入中塑在线网站###')    self.login()  # 先登录    self.driver.refresh()  # 刷新页面    self.status = 2  # 登录成功标识    print("###登录成功###")    if self.isElementExist('/html/body/div[4]/div[1]/div[2]/a[2]'):        self.driver.find_element(By.XPATH, '/html/body/div[4]/div[1]/div[2]/a[2]').click()
    • 调用login方法进行登录。

    • 刷新页面,并设置状态为登录成功。

    • 如果页面上存在特定元素,则点击该元素。

  • isElementExist:检查页面上是否存在特定的元素。

    def isElementExist(self, element):    try:        self.driver.find_element(By.XPATH, element)        return True    except:        return False
    • 尝试通过XPath查找元素,如果找到则返回True,否则返回False。

  • read_key:从用户输入的Excel文件中读取关键字和其他相关信息。

    #读取关键字文件def read_key(self):    file_path=input("输入关键字表格的文件名称:")    try:        # 使用pandas读取Excel文件        df = pd.read_excel(file_path)                    # 将起始时间和终止时间转换为yyyy-mm-dd格式的字符串        df['起始时间'] = pd.to_datetime(df['起始时间']).dt.strftime('%Y-%m-%d')        df['终止时间'] = pd.to_datetime(df['终止时间']).dt.strftime('%Y-%m-%d')                    # 将每个项目信息以字典的形式存储在一个列表中        projects = df.apply(lambda row: {            '产品名称': row['产品名称'],            '关键字': row['关键字'],            '起始时间': row['起始时间'],            '终止时间': row['终止时间']        }, axis=1).tolist()                    return projects    except Exception as e:        print(f"An error occurred: {e}")        return []
    • 提示用户输入文件名,读取Excel文件。

    • 将时间列转换为指定格式的字符串。

    • 将每个项目的信息存储为字典,并返回包含所有项目的列表。

  • search_item:根据关键字在网站上搜索商品。

    def search_item(self,item):    print(f"当前关键字为:{item}")    self.driver.find_element(By.XPATH, '/html/body/div[1]/div[2]/div[1]/div[2]/div[2]/div[9]/a').click()    sleep(2)  # 等待页面加载    self.driver.find_element(By.XPATH, '/html/body/div[1]/div[2]/div[2]/div[2]/div[4]/div/form/div[1]/input').send_keys(item)    self.driver.find_element(By.XPATH, '/html/body/div[1]/div[2]/div[2]/div[2]/div[4]/div/form/div[2]').click()    sleep(2)  # 等待页面加载
    • 打印当前搜索的关键字。

    • 点击搜索按钮,输入关键字,并执行搜索。

  • get_html:获取包含特定商品名称的历史价格链接。

    def get_html(self,project):    # 网页URL    item = project['关键字']    url = f'https://quote.21cp.com/home_centre/list/--.html?salesDivisionAreaSidList=&keyword={item}&quotedPriceDateRef=&isList=1'    history_price_link=0    try:        # 打开网页        self.driver.get(url)        while True:            # 等待表格元素加载完成            table = WebDriverWait(self.driver, 10).until(                EC.presence_of_element_located((By.TAG_NAME, "table"))            )                            # 定位到表格中的所有行            rows = table.find_elements(By.TAG_NAME, 'tr')            # 提取包含对应产品名称的历史价格链接            for row in rows:                # 定位产品名称所在的单元格                product_name_cells = row.find_elements(By.XPATH, ".//td[1]/a")                for cell in product_name_cells:                    if project['产品名称'] in cell.text:                        # 使用显式等待来确保链接是可见的                        try:                            first_link = WebDriverWait(row, 5).until(                                EC.presence_of_element_located((By.XPATH, ".//a[contains(., '历史价格')]"))                            )                            history_price_link=first_link.get_attribute('href')                                                                                    except:                            # 如果在某个行中没有找到链接,继续下一行                            continue            try:                # 获取下一页按钮                next_page = WebDriverWait(self.driver, 10).until(                    EC.presence_of_element_located((By.XPATH, "//*[@id='page']/div/a[2]"))                )                                        # 检查下一页按钮是否被禁用                if "layui-disabled" in next_page.get_attribute("class"):                    break  # 如果是最后一页,则退出循环                # 如果下一页按钮没有被禁用,则点击它                self.driver.execute_script("arguments[0].click();", next_page)            except:                return history_price_link                        #print(history_price_link)                    return history_price_link    except Exception as e:        print("An error occurred:", e)        return 0
    • 构造包含关键字的URL,打开网页。

    • 等待表格元素加载,并提取包含对应产品名称的历史价格链接。

  • set_time:在页面上设置起始和终止日期。

    def set_time(self,project):    start_date=project['起始时间']    end_date=project['终止时间']    # 输入起始日期    start_date_input = self.driver.find_element(By.XPATH, '//*[@id="startDate"]')    start_date_input.clear()    start_date_input.send_keys(start_date)    # 输入终止日期    end_date_input = self.driver.find_element(By.XPATH, '//*[@id="endDate"]')    end_date_input.clear()    end_date_input.send_keys(end_date)    if self.isElementExist('/html/body/div[1]/div[2]/div[2]/div[2]/div[2]/div[1]/form/div[3]'):        self.driver.find_element(By.XPATH, '/html/body/div[1]/div[2]/div[2]/div[2]/div[2]/div[1]/form/div[3]').click()
    • 获取日期输入框元素,清除原有内容,并输入项目中的起始和终止日期。

  • get_data_simple:根据项目信息抓取数据并保存为Excel文件。

    def get_data_simple(self,project):    link=self.get_html(project)    if link:        self.driver.get(link)        sleep(2)        self.driver.find_element(By.XPATH, '/html/body/div[1]/div[2]/div[2]/div[2]/div[2]/div[1]/form/div[1]/div[1]').click()        sleep(2)        data = []        # 获取页面左上角标题        page_title = self.driver.find_element(By.XPATH, '/html/body/div[1]/div[2]/div[2]/div[2]/div[1]/div[1]/div[1]').text        file_name = page_title.replace(' ', '_').replace('/', '_').replace('\\', '_') + '.xlsx'        item_folder_path = os.path.join(os.getcwd(), '爬取文件')  # 获取当前工作目录,并创建item文件夹的路径                    # 检查“爬取文件”文件夹是否存在,如果不存在则创建        if not os.path.exists(item_folder_path):            os.makedirs(item_folder_path)        print(f"当前项目为:{page_title}")                                self.set_time(project)        while True:            try:                # 等待表格元素加载完成                table = WebDriverWait(self.driver, 10).until(                    EC.presence_of_element_located((By.XPATH, "/html/body/div[1]/div[2]/div[2]/div[2]/div[2]/table"))                )                # 定位到表格中的所有行                rows = table.find_elements(By.TAG_NAME, 'tr')                # 提取表格数据                for row in rows[1:-1]:  # 第一行是表头,从第二行开始是数据                    cols = row.find_elements(By.TAG_NAME, 'td')                    cols_data = [col.text for col in cols]                    data.append(cols_data)                # 获取下一页按钮                next_page = WebDriverWait(self.driver, 10).until(                    EC.presence_of_element_located((By.XPATH, "//*[@id='page']/div/a[3]"))                )                #print(next_page.get_attribute("class"))                # 检查下一页按钮是否被禁用                if "layui-disabled" in next_page.get_attribute("class"):                    break  # 如果是最后一页,则退出循环                # 如果下一页按钮没有被禁用,则点击它                self.driver.execute_script("arguments[0].click();", next_page)            except TimeoutException:                print('此项目没有数据或日期超出范围,输出空文件')                print("------------------------------------------")                # 如果在指定时间内找不到下一页按钮,也认为是最后一页                break                        # 将文件保存到文件夹里        file_path = os.path.join(item_folder_path, file_name)  # 组合完整的文件路径        # 将数据转换为DataFrame        df = pd.DataFrame(data, columns=['更新日期', '价格(元/吨)', '涨跌', '涨跌值', '备注'])            # 存储到Excel文件        df.to_excel(file_path, index=False, engine='openpyxl')        print(f"数据已成功输出到{file_path}")        print("------------------------------------------")                else:        print("当前项目不存在,此项目信息为:")        print(project)        # 当前项目不存在时,将project信息追加存储到一个新的xlsx文件中        self.save_project_info_to_excel(project)
    • 获取历史价格链接,打开链接,设置时间范围。

    • 抓取表格数据,保存到Excel文件中。

  • save_project_info_to_excel:如果项目不存在,将项目信息保存到Excel文件中。

    def save_project_info_to_excel(self, project):    # 文件名和路径    file_name = '未找到项目信息.xlsx'    item_folder_path = os.path.join(os.getcwd(), '爬取文件')    if not os.path.exists(item_folder_path):        os.makedirs(item_folder_path)    file_path = os.path.join(item_folder_path, file_name)    # 检查文件是否存在,如果不存在则创建一个新的DataFrame    if not os.path.exists(file_path):        df = pd.DataFrame(columns=['产品名称', '关键字'])    else:        # 如果文件存在,读取文件内容        df = pd.read_excel(file_path)    # 将新的项目信息追加到DataFrame中    new_project_info = pd.DataFrame([project])    df = pd.concat([df, new_project_info], ignore_index=True)    # 存储到Excel文件    df.to_excel(file_path, index=False, engine='openpyxl')    print(f"项目信息已成功追加到{file_path}")    print("------------------------------------------")
    • 创建或读取未找到项目信息.xlsx文件,将项目信息追加到文件中。

  • get_data:遍历项目列表,对每个项目调用get_data_simple方法抓取数据。

    def get_data(self,projects):    for project in projects:        try:            self.get_data_simple(project)        except Exception as e:            print(f"An error occurred while processing project {project}: {e}")    print('导出完成')
    • 处理异常,并在所有项目处理完成后打印完成信息。

  • 主函数

if __name__ == '__main__':    try:        con = Concert()        con.enter_concert()        projects=con.read_key()        con.get_data(projects)    except Exception as e:        print(e)

3、运行步骤

  1. 初始化WebDriver

    • 实例化Concert类,创建Chrome WebDriver,设置浏览器启动时最大化窗口。

  2. 登录网站

    • 访问登录页面,等待页面加载,并提示用户扫码登录。

    • 扫码成功后,获取cookie,保存到本地文件cookies.pkl

    • 然后访问目标URL。

    • 根据self.login_method的值选择登录方式。

    • 如果选择Cookie登录(self.login_method == 1),则执行set_cookie方法:

    • 如果选择模拟登录(self.login_method == 0),则直接访问登录页面。

  3. 进入目标网站

    • 打开浏览器,进入中塑在线网站。

    • 登录后刷新页面,将状态设置为登录成功。

    • 如果页面上存在特定元素,则点击该元素。

    • 执行enter_concert方法:

  4. 读取关键字文件

    • 提示用户输入关键字表格的文件名称。

    • 使用pandas读取Excel文件,并将时间列转换为指定格式。

    • 将每个项目信息以字典形式存储在列表中。

    • 执行read_key方法:

  5. 搜索商品

    • 点击搜索按钮,输入关键字,并执行搜索。

    • 等待搜索结果页面加载。

    • 对于每个关键字,执行search_item方法:

  6. 获取商品历史价格链接

    • 构造包含关键字的URL,打开网页。

    • 提取包含对应产品名称的历史价格链接。

    • 对于每个搜索结果,执行get_html方法:

  7. 设置时间范围

    • 在页面上设置起始和终止日期。

    • 执行set_time方法:

  8. 抓取数据并保存为Excel文件

    • 根据项目信息抓取数据。

    • 如果数据存在,则保存到Excel文件中。

    • 如果项目不存在,则调用save_project_info_to_excel方法,将项目信息保存到Excel文件中。

    • 执行get_data_simple方法:

  9. 遍历项目列表并抓取数据

    • 遍历项目列表,对每个项目调用get_data_simple方法抓取数据。

    • 处理异常,并在所有项目处理完成后打印完成信息。

    • 执行get_data方法:

  10. 主程序执行

    • 创建Concert类的实例。

    • 执行登录,读取关键字文件。

    • 抓取数据。


4、所有代码

import osimport picklefrom time import sleepfrom selenium import webdriverfrom selenium.webdriver.common.by import Byfrom selenium.webdriver.support.ui import WebDriverWaitfrom selenium.webdriver.support import expected_conditions as ECimport pandas as pdfrom selenium.common.exceptions import TimeoutExceptionfrom selenium.webdriver.chrome.options import Optionsfrom selenium import webdriver# 行情网主页hangqing_url = "https://quote.21cp.com/"# 登录页login_url = "https://passport.21cp.com/auth/realms/zs-web/protocol/openid-connect/auth?response_type=code&client_id=zs-price-quote-web&redirect_uri=https%3A%2F%2Fquote.21cp.com%2Fsso%2Flogin&state=4e8a01e9-170f-4dda-bc27-8b43f9255aa2&login=true&scope=openid"# 石化出厂价目标页target_url = 'https://quote.21cp.com/home_centre/list/--.html'class Concert:    def __init__(self):        self.status = 0         # 状态,表示如今进行到何种程度        self.login_method = 1   # {0:模拟登录,1:Cookie登录}自行选择登录方式        chrome_options = Options()        chrome_options.add_argument("start-maximized")  # 启动时最大化窗口        self.driver = webdriver.Chrome(options=chrome_options)    def set_cookie(self):        self.driver.get(login_url)        sleep(2)  # 等待页面加载        while self.driver.title.find('账号登录-中塑在线-21世纪塑料行业门户') == -1:            sleep(1)        print('###请扫码登录###')        # 最大化浏览器窗口        self.driver.maximize_window()        sleep(2)  # 等待页面加载        while self.driver.title == '账号登录-中塑在线-21世纪塑料行业门户':            sleep(1)        print("###扫码成功###")        cookies = self.driver.get_cookies()        with open("cookies.pkl", "wb") as f:            pickle.dump(cookies, f)        print("###Cookie保存成功###")        self.driver.get(target_url)    def get_cookie(self):        try:            cookies = pickle.load(open("cookies.pkl", "rb"))  # 载入cookie            for cookie in cookies:                self.driver.add_cookie(cookie)            print('###载入Cookie###')        except Exception as e:            print(e)    def login(self):        if self.login_method == 0:            self.driver.get(login_url)            print('###开始登录###')        elif self.login_method == 1:            self.set_cookie()                    def enter_concert(self):        """打开浏览器"""        print('###打开浏览器,进入中塑在线网站###')        self.login()  # 先登录        self.driver.refresh()  # 刷新页面        self.status = 2  # 登录成功标识        print("###登录成功###")        if self.isElementExist('/html/body/div[4]/div[1]/div[2]/a[2]'):            self.driver.find_element(By.XPATH, '/html/body/div[4]/div[1]/div[2]/a[2]').click()    def isElementExist(self, element):        try:            self.driver.find_element(By.XPATH, element)            return True        except:            return False        #读取关键字文件    def read_key(self):        file_path=input("输入关键字表格的文件名称:")        try:            # 使用pandas读取Excel文件            df = pd.read_excel(file_path)                        # 将起始时间和终止时间转换为yyyy-mm-dd格式的字符串            df['起始时间'] = pd.to_datetime(df['起始时间']).dt.strftime('%Y-%m-%d')            df['终止时间'] = pd.to_datetime(df['终止时间']).dt.strftime('%Y-%m-%d')                        # 将每个项目信息以字典的形式存储在一个列表中            projects = df.apply(lambda row: {                '产品名称': row['产品名称'],                '关键字': row['关键字'],                '起始时间': row['起始时间'],                '终止时间': row['终止时间']            }, axis=1).tolist()                        return projects        except Exception as e:            print(f"An error occurred: {e}")            return []    def search_item(self,item):        print(f"当前关键字为:{item}")        self.driver.find_element(By.XPATH, '/html/body/div[1]/div[2]/div[1]/div[2]/div[2]/div[9]/a').click()        sleep(2)  # 等待页面加载        self.driver.find_element(By.XPATH, '/html/body/div[1]/div[2]/div[2]/div[2]/div[4]/div/form/div[1]/input').send_keys(item)        self.driver.find_element(By.XPATH, '/html/body/div[1]/div[2]/div[2]/div[2]/div[4]/div/form/div[2]').click()        sleep(2)  # 等待页面加载    def get_html(self,project):        # 网页URL        item = project['关键字']        url = f'https://quote.21cp.com/home_centre/list/--.html?salesDivisionAreaSidList=&keyword={item}&quotedPriceDateRef=&isList=1'        history_price_link=0        try:            # 打开网页            self.driver.get(url)            while True:                # 等待表格元素加载完成                table = WebDriverWait(self.driver, 10).until(                    EC.presence_of_element_located((By.TAG_NAME, "table"))                )                                # 定位到表格中的所有行                rows = table.find_elements(By.TAG_NAME, 'tr')                # 提取包含对应产品名称的历史价格链接                for row in rows:                    # 定位产品名称所在的单元格                    product_name_cells = row.find_elements(By.XPATH, ".//td[1]/a")                    for cell in product_name_cells:                        if project['产品名称'] in cell.text:                            # 使用显式等待来确保链接是可见的                            try:                                first_link = WebDriverWait(row, 5).until(                                    EC.presence_of_element_located((By.XPATH, ".//a[contains(., '历史价格')]"))                                )                                history_price_link=first_link.get_attribute('href')                                                                                        except:                                # 如果在某个行中没有找到链接,继续下一行                                continue                try:                    # 获取下一页按钮                    next_page = WebDriverWait(self.driver, 10).until(                        EC.presence_of_element_located((By.XPATH, "//*[@id='page']/div/a[2]"))                    )                                            # 检查下一页按钮是否被禁用                    if "layui-disabled" in next_page.get_attribute("class"):                        break  # 如果是最后一页,则退出循环                    # 如果下一页按钮没有被禁用,则点击它                    self.driver.execute_script("arguments[0].click();", next_page)                except:                    return history_price_link                            #print(history_price_link)                        return history_price_link        except Exception as e:            print("An error occurred:", e)            return 0    def set_time(self,project):        start_date=project['起始时间']        end_date=project['终止时间']        # 输入起始日期        start_date_input = self.driver.find_element(By.XPATH, '//*[@id="startDate"]')        start_date_input.clear()        start_date_input.send_keys(start_date)        # 输入终止日期        end_date_input = self.driver.find_element(By.XPATH, '//*[@id="endDate"]')        end_date_input.clear()        end_date_input.send_keys(end_date)        if self.isElementExist('/html/body/div[1]/div[2]/div[2]/div[2]/div[2]/div[1]/form/div[3]'):            self.driver.find_element(By.XPATH, '/html/body/div[1]/div[2]/div[2]/div[2]/div[2]/div[1]/form/div[3]').click()    def get_data_simple(self,project):        link=self.get_html(project)        if link:            self.driver.get(link)            sleep(2)            self.driver.find_element(By.XPATH, '/html/body/div[1]/div[2]/div[2]/div[2]/div[2]/div[1]/form/div[1]/div[1]').click()            sleep(2)            data = []            # 获取页面左上角标题            page_title = self.driver.find_element(By.XPATH, '/html/body/div[1]/div[2]/div[2]/div[2]/div[1]/div[1]/div[1]').text            file_name = page_title.replace(' ', '_').replace('/', '_').replace('\\', '_') + '.xlsx'            item_folder_path = os.path.join(os.getcwd(), '爬取文件')  # 获取当前工作目录,并创建item文件夹的路径                        # 检查“爬取文件”文件夹是否存在,如果不存在则创建            if not os.path.exists(item_folder_path):                os.makedirs(item_folder_path)            print(f"当前项目为:{page_title}")                                    self.set_time(project)            while True:                try:                    # 等待表格元素加载完成                    table = WebDriverWait(self.driver, 10).until(                        EC.presence_of_element_located((By.XPATH, "/html/body/div[1]/div[2]/div[2]/div[2]/div[2]/table"))                    )                    # 定位到表格中的所有行                    rows = table.find_elements(By.TAG_NAME, 'tr')                    # 提取表格数据                    for row in rows[1:-1]:  # 第一行是表头,从第二行开始是数据                        cols = row.find_elements(By.TAG_NAME, 'td')                        cols_data = [col.text for col in cols]                        data.append(cols_data)                    # 获取下一页按钮                    next_page = WebDriverWait(self.driver, 10).until(                        EC.presence_of_element_located((By.XPATH, "//*[@id='page']/div/a[3]"))                    )                    #print(next_page.get_attribute("class"))                    # 检查下一页按钮是否被禁用                    if "layui-disabled" in next_page.get_attribute("class"):                        break  # 如果是最后一页,则退出循环                    # 如果下一页按钮没有被禁用,则点击它                    self.driver.execute_script("arguments[0].click();", next_page)                except TimeoutException:                    print('此项目没有数据或日期超出范围,输出空文件')                    print("------------------------------------------")                    # 如果在指定时间内找不到下一页按钮,也认为是最后一页                    break                            # 将文件保存到文件夹里            file_path = os.path.join(item_folder_path, file_name)  # 组合完整的文件路径            # 将数据转换为DataFrame            df = pd.DataFrame(data, columns=['更新日期', '价格(元/吨)', '涨跌', '涨跌值', '备注'])                # 存储到Excel文件            df.to_excel(file_path, index=False, engine='openpyxl')            print(f"数据已成功输出到{file_path}")            print("------------------------------------------")                    else:            print("当前项目不存在,此项目信息为:")            print(project)            # 当前项目不存在时,将project信息追加存储到一个新的xlsx文件中            self.save_project_info_to_excel(project)    def save_project_info_to_excel(self, project):        # 文件名和路径        file_name = '未找到项目信息.xlsx'        item_folder_path = os.path.join(os.getcwd(), '爬取文件')        if not os.path.exists(item_folder_path):            os.makedirs(item_folder_path)        file_path = os.path.join(item_folder_path, file_name)        # 检查文件是否存在,如果不存在则创建一个新的DataFrame        if not os.path.exists(file_path):            df = pd.DataFrame(columns=['产品名称', '关键字'])        else:            # 如果文件存在,读取文件内容            df = pd.read_excel(file_path)        # 将新的项目信息追加到DataFrame中        new_project_info = pd.DataFrame([project])        df = pd.concat([df, new_project_info], ignore_index=True)        # 存储到Excel文件        df.to_excel(file_path, index=False, engine='openpyxl')        print(f"项目信息已成功追加到{file_path}")        print("------------------------------------------")            def get_data(self,projects):        for project in projects:            try:                self.get_data_simple(project)            except Exception as e:                print(f"An error occurred while processing project {project}: {e}")        print('导出完成')if __name__ == '__main__':    try:        con = Concert()        con.enter_concert()        projects=con.read_key()        con.get_data(projects)    except Exception as e:        print(e)

Tips:运行之后只需要手动完成登录操作,和表格文件名输入操作即可。爬取就交给程序啦。


作者的话:

        制作不易,点赞or转发or再看or赞赏or关注 支持一下呗

图片

相关链接:

Python爬虫实战(保姆级自动登录教程)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2266936.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

国产三维CAD正强势崛起

CAD软件作为现代工业设计和制造领域不可或缺的核心工具,其重要性不言而喻。它极大地提升了设计效率与精度,缩短了产品开发周期,为企业的创新与发展注入了强大动力。随着全球市场竞争的日益激烈,以及当前国际局势的复杂多变&#x…

编码滤波技术-SAO

1. AVS中的SAO样值偏移自适应补偿技术,首先将正在处理的块往左上移动了四行四列,超过图像边界的部分丢弃,右、下图像边界部分补齐。 也就是偏移前在图像边缘的块,进行去除和扩展得到偏移后的块。图像内部的块,正常往左…

Leetcode打卡:查询数组中元素出现的位置

执行结果:通过 题目 3159 查询数组中元素出现的位置 给你一个整数数组 nums ,一个整数数组 queries 和一个整数 x 。 对于每个查询 queries[i] ,你需要找到 nums 中第 queries[i] 个 x 的位置,并返回它的下标。如果数组中 x 的出…

【游戏设计原理】32 - 消费者剩余

1. 如何理解消费者剩余原理? 消费者剩余是一种经济学概念,表示消费者愿意为商品支付的最大金额与实际支付金额之间的差额。 简单来说,消费者剩余衡量了消费者从交易中获得的“额外价值”或“剩余利益”。 在传统商业模式下,由于…

肝功能不正常可以过教师入职体检吗?

如何看肝功能报告单 转氨酶正常等于肝功能正常吗?要想看懂肝功能报告单就要看懂各指标含义。 1、总胆红素TbiL正常值是 1.7-17.1μmol/L 急性黄疸型肝炎活动性肝炎肝坏死、肝癌、胰头癌都异常偏高。 2、直接胆红素 DbiL正常值是 0-6.84μmol/L 结石病、肝癌、胰头癌与这项…

CH340系列芯片驱动电路·CH340系列芯片驱动!!!

目录 CH340基础知识 CH340常见类型 CH340引脚功能讲解 CH340驱动电路 CH340系列芯片数据手册 编写不易,仅供学习,请勿搬运,感谢理解 常见元器件驱动电路文章专栏连接 LM7805系列降压芯片驱动电路降压芯片驱动电路详解-CSDN博客 ME62…

(公开源码)基于springboot+vue的在线课程教学管理系统 计算机毕业设计P10046

项目说明 本号所发布的项目均由我部署运行验证,可保证项目系统正常运行,以及提供完整源码。 如需要远程部署/定制/讲解系统,可以联系我。定制项目未经同意不会上传! 项目源码获取方式放在文章末尾处 注:项目仅供学…

UE5 把场景转成HDR图

目录 使用影片渲染队列 使用影片渲染队列 以下方法实测 UE5.4 有效 1.打开影片渲染队列窗口。依次打开:窗口—过场动画—影片渲染队列 2.添加Sequence动画。点击“渲染”按钮,选择要渲染的Sequence。 3.设置输出配置。 点击“Unsaved Config”打开配置…

使用RKNN进行YOLOv8人体姿态估计的实战教程:yolov8-pose.onnx转yolov8-pose.rknn+推理全流程

之前文章有提到“YOLOv8的原生模型包含了后处理步骤,其中一些形状超出了RK3588的矩阵计算限制,因此需要对输出层进行一些裁剪”,通过裁剪后得到的onnx能够顺利的进行rknn转换,本文将对转rnkk过程,以及相应的后处理进行阐述。并在文末附上全部源码、数据、模型的百度云盘链…

嵌入式硬件杂谈(八)电源的“纹波”到底是什么?

纹波的引入:在我们嵌入式设备中,很多时候电路电源的纹波很敏感,纹波太大会导致系统不工作,因此设计一个纹波很小的电路就是我们的需求了。 电路的纹波是什么? 纹波(Ripple)是指电源输出中叠加在…

水电站视频智能监控系统方案设计与技术应用方案

一、背景需求 水电站作为国家重要的能源基地,其安全运行对于保障能源供应和社会稳定具有重要意义。然而,传统的人工监控方式存在着诸多问题,如人力成本高、监控范围有限、反应不及时等。因此,水电站急需引进一种先进的视频智能监控…

MAC M4安装QT使用国内镜像源在线安装

MAC M4安装QT使用国内镜像源在线安装 一、下载安装包1. 访问[https://www.qt.io/](https://www.qt.io/)下载在线安装包2. 下载结果 二、创建QT账户,安装的时候需要三、安装1. 终端打开安装包2. 指定安装源3. 运行安装完的QT 一、下载安装包 1. 访问https://www.qt.…

实现类似gpt 打字效果

1. css的动画(animation) css中实现动画有两种方式:transition过渡动画、 animation自定义动画。 具体的可以看MDN链接:https://developer.mozilla.org/zh-CN/docs/Web/CSS/animation 使用keyframes自定义关键帧动画并未其命名使用自定义动…

CV(7)--神经网络训练

前言 仅记录学习过程,有问题欢迎讨论 什么是神经网络: 神经网络是一种模拟人脑神经元工作原理的算法,它由多个神经元组成,每个神经元都接受输入,通过计算产生输出,并将输出传递给其他神经元。神经网络的…

python实战案例笔记:统计出数据中路劲下没有文件的文件夹

数据样例:👇有如下excel数据 需求:有如下excel,a.xls,统计出路劲下没有文件的路劲 详细实现代码: import os from openpyxl import Workbook from datetime import datetimedef get_empty_dirs(paths):# …

API安全学习笔记

必要性 前后端分离已经成为web的一大趋势,通过TomcatNgnix(也可以中间有个Node.js),有效地进行解耦。并且前后端分离会为以后的大型分布式架构、弹性计算架构、微服务架构、多端化服务(多种客户端,例如:浏览器&#x…

金仓数据库对象访问权限的管理

基础知识 对象的分类 数据库的表、索引、视图、缺省值、规则、触发器等等,都称为数据库对象,对象分为如下两类: 模式(SCHEMA)对象:可以理解为一个存储目录,包含视图、索引、数据类型、函数和操作符等。非模式对象:其他的数据库对象&#x…

【连续学习之ResCL算法】2020年AAAI会议论文:Residual continual learning

1 介绍 年份:2020 会议: AAAI Lee J, Joo D, Hong H G, et al. Residual continual learning[C]//Proceedings of the AAAI Conference on Artificial Intelligence. 2020, 34(04): 4553-4560. 本文提出的算法是Residual Continual Learning (ResC…

超时空跑跑新手池抽什么比较好 超时空跑跑风火水雷配队搭配

在超时空跑跑这款游戏中,各种角色分为风、火、水、雷四类,我们可以根据新手池抽出的角色进行搭配,今天就给大家推荐一下四种属性分别适合的队伍。 一、风系队 阵容搭配:关偃月方源少阳 1.关偃月的弹指次数可以持续很长的时间&am…

PHP实现登录和注册(附源码)

前言 本博客主要讲述利用php环境实现一个简单的前后端结合的用户登录和注册功能。phpstudy是PHP调试环境的集成包,该程序包集成了 ApachePHPMySQLphpMyAdmin 等多个工具,是很好用的调试环境的程序集成包。 目录 前言 1. 准备工作 1.1 工具 1.2 php…