当前位置: 首页 > news >正文

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

此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爬虫实战(保姆级自动登录教程)

相关文章:

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

此blog为爬虫实战教学,代码已附上,可以复制运行。若要直接看实战代码翻到博客后半部分。 本文使用selenium库进行爬虫,实现爬取数据操作,此库是通过模仿用户的操作进行对页面的处理。了解了这个思维模式,可以对代码进…...

探索CSDN博客数据:使用Python爬虫技术

探索CSDN博客数据:使用Python爬虫技术 在数字化的浪潮中,数据的获取与分析变得日益关键。CSDN作为中国领先的IT社区和服务平台,汇聚了海量的技术博客与文章,成为一座蕴藏丰富的数据宝库。本文将引领您穿梭于Python的requests和py…...

PPT画图——如何设置导致图片为600dpi

winr,输入regedit打开注册表 按路径找,HKEY_CURRENT_USER\Software\Microsoft\Office\XX.0\PowerPoint\Options(xx为版本号,16.0 or 15.0或则其他)。名称命名:ExportBitmapResolution 保存即可,…...

uniapp——APP读取bin文件,解析文件的数据内容(二)

文章目录 读取bin文件内容,发送给蓝牙设备;上传文件返回数据格式通过URL路径获取文件对象,读取文件的数据内容file对象返回数据格式 读取bin文件内容,发送给蓝牙设备; 上传文件,根据返回路径,解…...

Paddler负载均衡器

Paddler负载均衡器 Paddler本身是用Go语言编写的,没有直接的Python接口,但可以通过以下方式在Python中使用: 执行命令行调用 在Python中可以使用 subprocess 模块来调用Paddler的命令行工具,实现负载均衡功能 。例如: import subprocessdef start_paddler_agent():com…...

`we_chat_union_id IS NOT NULL` 和 `we_chat_union_id != ‘‘` 这两个条件之间的区别

文章目录 1、什么是空字符串?2、两个引号之间加上空格 好的,我们来详细解释一下 we_chat_union_id IS NOT NULL 和 we_chat_union_id ! 这两个条件之间的区别,以及它们在 SQL 查询中的作用: 1. we_chat_union_id IS NOT NULL 含…...

clicbot可立宝编程 易错归纳笔记

1、屏幕播放表情模块和等待时间 易错点1: (1)等待时间: (a)不是等上一个代码执行完,再执行等待时间,这是错误的。 (b)等待时间上面的代码1刚开始执行,上面的代码2也刚开始执行,不是等到代码1执行完&#xf…...

MySQL 数据”丢失”事件之 binlog 解析应用

事件背景 客户反馈在晚间数据跑批后,查询相关表的数据时,发现该表的部分数据在数据库中不存在 从应用跑批的日志来看,跑批未报错,且可查到日志中明确显示当时那批数据已插入到数据库中 需要帮忙分析这批数据丢失的原因。 备注:考虑信息敏感性,以下分析场景测试环境模拟,相关数据…...

基于人工智能时代政务智慧转型的实现前景初探

去年6月,我有幸聆听了由华政公共管理与政治学院精心组织的2019年MPA研究生高端论坛,上午场:由董海军(中共上海市委机构编制委员会办公室处长)主讲的深化机构改革的探索与实践,以及下午场:由束金…...

【论文笔记】Visual Alignment Pre-training for Sign Language Translation

🍎个人主页:小嗷犬的个人主页 🍊个人网站:小嗷犬的技术小站 🥭个人信条:为天地立心,为生民立命,为往圣继绝学,为万世开太平。 基本信息 标题: Visual Alignment Pre-tra…...

一起学Git【第五节:git版本回退】

git reset 是 Git 版本控制系统中一个非常强大的命令,它可以用来重置当前分支到指定的状态,即执行撤销操作或者回退至之前的某一版本,他可以回退至之前的某一个提交状态。有三种主要的用法:git reset --soft;git reset --hard;git reset --mixed; 对比如图: 1.git res…...

金蝶V10中间件的使用

目录 环境准备搭建过程配置修改应用部署 环境准备 Linux内核服务器JDK1.8安装包:AAS-V10.zip程序包:***.war 搭建过程 将安装包上传至服务器opt目录下,官方给定的默认服务主目录为“/opt/AAS-V10/ApusicAS/aas/”;解压安装包(解…...

hi168大数据离线项目环境搭建

hi168大数据离线项目环境搭建 ## **1. 服务器准备**##### 1.1 创建集群应用节点 集群服务器使用“我的应用“中的Ubuntu22.04集群模版创建三个节点应用,并且进入“我的应用”中去修改一下节点名称(node1对应master,node2对应hadoop1&#xf…...

Ubuntu 22.04安装Docker

陈拓 2024/10/19-2024/12/26 0. 概述 docker是容器(Container),有点像一个轻量级的虚拟机。 容器是一种轻量级、可移植、并将应用程序进行的打包的技术,使应用程序可以在几乎任何地方以相同的方式运行。Docker将镜像文件运行起…...

穿山甲等广告联盟依据哪些维度给APP、小程序结算广告变现收益

媒体在开展广告变现商业化时,最关心的是变现收益问题,所运营的不同体量的APP、小程序能产生多少广告变现收益。#广告联盟# 广告变现的价格、收益不是一成不变的,广告转化是影响广告收益的重要因素之一。广告平台针对整个变现链路上的各环节&…...

【ES6复习笔记】迭代器(10)

什么是迭代器? 迭代器(Iterator)是一种对象,它能够遍历并访问一个集合中的元素。在 JavaScript 中,迭代器提供了一种统一的方式来处理各种集合,如数组、字符串、Map、Set 等。通过迭代器,我们可…...

ROS1入门教程6:复杂行为处理

一、新建项目 # 创建工作空间 mkdir -p demo6/src && cd demo6# 创建功能包 catkin_create_pkg demo roscpp rosmsg actionlib_msgs message_generation tf二、创建行为 # 创建行为文件夹 mkdir action && cd action# 创建行为文件 vim Move.action# 定义行为…...

【 Copilot】云开发 Copilot 实战教程:从入门到精通,掌握云开发核心技能

我的个人主页 我的领域:人工智能篇,希望能帮助到大家!!!👍点赞 收藏❤ 引言 云开发 Copilot 作为一款革新性的开发辅助工具,利用先进的人工智能技术,为开发者在云开发的征程中点亮…...

DataCap MongoDB Driver: 全面解析MongoDB在DataCap中的使用指南

在大数据时代,MongoDB作为一款广受欢迎的NoSQL数据库,其灵活的文档存储模型和强大的查询能力使其成为许多现代应用的首选数据存储方案。今天,我们将深入探讨DataCap MongoDB Driver,这是一个强大的工具,它让在DataCap环…...

[x86 ubuntu22.04]双触摸屏的触摸事件都响应在同一个触摸屏上

1 问题描述 CPU:G6900E OS:ubuntu22.04 Kernel:6.8.0-49-generic 系统下有两个一样的 edp 触摸屏,两个触摸屏的触摸事件都响应在同一个 edp 屏幕上。 2 解决过程 使用“xinput”命令查看输入设备,可以看到只有一个 to…...

Linux:SystemV通信

目录 一、System V通信 二、共享内存 代码板块 总结 一、System V通信 System V IPC(inter-process communication),是一种进程间通信方式。其实现的方法有共享内存、消息队列、信号量这三种机制。 本文着重介绍共享内存这种方式。 二、共…...

全面Kafka监控方案:从配置到指标

文章目录 1.1.监控配置1.2.监控工具1.3.性能指标系统相关指标GC相关指标JVM相关指标Topic相关指标Broker相关指标 1.4.性能指标说明1.5.重要指标说明 1.1.监控配置 开启JMX服务端口:kafka基本分为broker、producer、consumer三个子项,每一项的启动都需要…...

Springboot项目Druid运行时动态连接多数据源的功能

项目支持多数据库连接是个很常见的需求&#xff0c;这不仅是要在编译前连已经知道的多个数据库&#xff0c;有时还要在程序运行时连后期增加的多个数据源来获得数据。 一、编译前注册数据库连接 1.引入依赖包 <!-- springboot 3.x --><dependency><groupId&g…...

【漏洞复现】F5 BIG-IP Next Central Manager SQL注入漏洞(CVE-2024-26026)

免责声明 请勿利用文章内的相关技术从事非法测试,由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,作者不为此承担任何责任。工具来自网络,安全性自测,如有侵权请联系删除。本次测试仅供学习使用,如若非法他用,与平台和本文作…...

中间件xxl-job安装

拉取镜像 docker pull xuxueli/xxl-job-admin:2.4.2 创建xxl-job-admin容器 docker create --name xxl-job-admin -p 9099:8080 -e PARAMS"--spring.datasource.urljdbc:mysql://192.168.96.57:3306/xxl_job2Unicodetrue&characterEncodingUTF-8 --spring.dataso…...

Pytorch | 利用SMI-FGRM针对CIFAR10上的ResNet分类器进行对抗攻击

Pytorch | 利用I-FGSSM针对CIFAR10上的ResNet分类器进行对抗攻击 CIFAR数据集SMI-FGRM介绍SMI-FGRM算法流程 SMI-FGRM代码实现SMI-FGRM算法实现攻击效果 代码汇总smifgrm.pytrain.pyadvtest.py 之前已经针对CIFAR10训练了多种分类器&#xff1a; Pytorch | 从零构建AlexNet对CI…...

论文解读 | EMNLP2024 一种用于大语言模型版本更新的学习率路径切换训练范式

点击蓝字 关注我们 AI TIME欢迎每一位AI爱好者的加入&#xff01; 点击 阅读原文 观看作者讲解回放&#xff01; 作者简介 王志豪&#xff0c;厦门大学博士生 刘诗雨&#xff0c;厦门大学硕士生 内容简介 新数据的不断涌现使版本更新成为大型语言模型&#xff08;LLMs&#xff…...

破解海外业务困局:新加坡服务器托管与跨境组网策略

在当今全球化商业蓬勃发展的浪潮之下&#xff0c;众多企业将目光投向海外市场&#xff0c;力求拓展业务版图、抢占发展先机。而新加坡&#xff0c;凭借其卓越的地理位置、强劲的经济发展态势以及高度国际化的营商环境&#xff0c;已然成为企业海外布局的热门之选。此时&#xf…...

win系统B站播放8k视频启用HEVC编码

下载HEVC插件 点击 HEVC Video Extension 2.2.20.0 latest downloads&#xff0c;根据教程下载安装 安装 Random User-Agent 点击 Random User-Agent 安装 配置 Random User-Agent ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/dda0ea75096c42c0a79ef6f6f5521…...

Pion WebRTC 项目教程

Pion WebRTC 项目教程 webrtc Pure Go implementation of the WebRTC API [这里是图片001] 项目地址: https://gitcode.com/gh_mirrors/we/webrtc 1. 项目目录结构及介绍 Pion WebRTC 项目的目录结构如下&#xff1a; pion/webrtc ├── api ├── examples ├── inter…...

Opencv之对图片的处理和运算

Opencv实现对图片的处理和修改 目录 Opencv实现对图片的处理和修改灰度图读取灰度图转换灰度图 RBG图单通道图方法一方法二 单通道图显色合并单通道图 图片截取图片打码图片组合缩放格式1格式2 图像运算图像ma[m:n,x:y]b[m1:n1,x1:y1] add加权运算 灰度图 读取灰度图 imread(‘…...

基于cobra开发的k8s命令行管理工具k8s-manager

基于cobra开发的k8s命令行管理工具k8s-manager 如果觉得好用&#xff0c;麻烦给个Star!通用配置1 node 分析所有node的资源情况2 analysis 分析Node节点上的资源使用构成3 image 获取指定namespace的所有镜像地址4 resource 获取指定namespace的所有limit 与 Requests大小5 top…...

基于NodeMCU的物联网空调控制系统设计

最终效果 基于NodeMCU的物联网空调控制系统设计 项目介绍 该项目是“物联网实验室监测控制系统设计&#xff08;仿智能家居&#xff09;”项目中的“家电控制设计”中的“空调控制”子项目&#xff0c;最前者还包括“物联网设计”、“环境监测设计”、“门禁系统设计计”和“小…...

springboot/ssm图书大厦图书管理系统Java代码编写web图书借阅项目

springboot/ssm图书大厦图书管理系统Java代码编写web图书借阅项目 基于springboot(可改ssm)vue项目 开发语言&#xff1a;Java 框架&#xff1a;springboot/可改ssm vue JDK版本&#xff1a;JDK1.8&#xff08;或11&#xff09; 服务器&#xff1a;tomcat 数据库&#xff…...

【MySQL】踩坑笔记——保存带有换行符等特殊字符的数据,需要进行转义保存

问题描述 从DBeaver中导出了部分业务数据的 insert sql&#xff0c;明明在开发、测试环境都可以一把执行通过&#xff0c;却在预发环境执行前的语法检查失败了&#xff0c;提示有SQL语法错误。 这条SQL长这样&#xff0c;default_sql是要在odps上执行的sql语句&#xff0c;提…...

利用 Python 编写一个 VIP 音乐下载脚本

在这篇博客中,我们将介绍如何使用 Python 编写一个简单的 VIP 音乐下载脚本,利用网页爬虫技术从一个音乐网站下载歌曲。通过解析网页,获取歌曲的真实下载链接,并将音乐文件保存到本地。我们将使用 requests 和 BeautifulSoup 库来实现这个过程。 目标 本脚本的主要功能是…...

Sashulin升级啦,开箱即用!

经过多年的不断投入&#xff0c;升级为了Sashulin基础软件系列&#xff0c;本系列包含&#xff1a; 1、Sashulin IDE 2025全域通用开发工具 通用型Java开发工具&#xff0c;并可以进行业务流可视化开发。 2、发布Sashulin Webserver 2025 将Html等网页文件发布成网站&#xf…...

Java圣诞树

目录 写在前面 技术需求 程序设计 代码分析 一、代码结构与主要功能概述 二、代码功能分解与分析 1. 类与常量定义 2. 绘制树的主逻辑 3. 彩色球的绘制 4. 动态效果的实现 5. 窗口初始化 三、关键特性与优点 四、总结 写在后面 写在前面 Java语言绘制精美圣诞树…...

在Python如何用Type创建类

文章目录 一&#xff0c;如何创建类1&#xff1a;创建一个简单类2&#xff1a;添加属性和方法3&#xff1a;动态继承父类4&#xff1a;结合元类的使用总结 二.在什么情境下适合使用Type创建类1. **运行时动态生成类**2. **避免重复代码**3. **依赖元类或高级元编程**4. **动态扩…...

04软件测试需求分析案例-用户登录

通读文档&#xff0c;提取信息&#xff0c;提出问题&#xff0c;整理为需求。 从需求规格说明、设计说明、配置说明等文档获取原始需求&#xff0c;通读原始需求&#xff0c;分析有哪些功能&#xff0c;每种功能要完成什么业务&#xff0c;业务该如何实现&#xff0c;业务逻辑…...

替代传统FTP传输,镭速大数据传输系统实现安全高效数据流转!

信息技术的快速进步让大数据成为了企业决策的关键支撑&#xff0c;但同时也带来了巨大的挑战。企业在运营过程中产生的数据量急剧增加&#xff0c;这对数据传输的速度、安全性和效率提出了更高的要求。然而&#xff0c;传统的FTP传输方式在处理大规模数据时显得力不从心&#x…...

SpringMVC学习(一)——请求与响应处理

目录 一、SpringMVC简介 二、RequestMapping&#xff1a;请求路径映射 三、RestController 四、请求限定 五、请求处理 1.使用普通变量&#xff0c;收集请求参数 2.使用RequestParam明确指定获取参数 3.目标方法参数是一个pojo 4.RequestHeader&#xff1a;获取请求…...

大语言模型学习工具及资源总结和落地应用

当前&#xff0c;随着人工智能技术的迅猛发展&#xff0c;大语言模型&#xff08;Large Language Models, LLMs&#xff09;在各个领域的应用日益广泛。以下是国内外常见的大语言模型工具、已经落地部署的应用以及学习相关的网站和资源的详细介绍。 一、国内外常见的大语言模型…...

深度学习使用Anaconda打开Jupyter Notebook编码

新手入门深度学习使用Anaconda打开Jupyter Notebook编码 1. 安装Anaconda 第一种是Anaconda官网下载安装包&#xff0c;但是很慢&#xff0c;不太建议 第二种使用国内清华大学镜像源下载 选择适合自己电脑的版本&#xff0c;支持windows&#xff0c;linux系统 下载完之后自行…...

【视觉惯性SLAM:四、相机成像模型】

相机成像模型介绍 相机成像模型是计算机视觉和图像处理中的核心内容&#xff0c;它描述了真实三维世界如何通过相机映射到二维图像平面。相机成像模型通常包括针孔相机的基本成像原理、数学模型&#xff0c;以及在实际应用中如何处理相机的各种畸变现象。 一、针孔相机成像原…...

Firewalld 防火墙详解:深入理解与实践指南

在现代网络环境中&#xff0c;防火墙是保护系统和网络不受未授权访问的关键工具。firewalld是Linux系统中广泛使用的动态防火墙管理工具&#xff0c;它提供了强大的功能和灵活的配置选项。本文将深入探讨firewalld防火墙的工作原理、配置和管理&#xff0c;以及如何在实际环境中…...

在linux系统中使用jdbc访问sqlite数据库时报错“java.lang.UnsatisfiedLinkError”

1. 异常描述 在linux系统中使用jdbc访问sqlite数据库时出现如下错误提示&#xff1a; 2. 异常分析 可能是当前使用版本的sqlite-jdbc-xxx.jar版本有bug。 3. 异常解决 我是从3.8.9.1版本换到了3.16.1版本就好了。...

华为管理变革之道:管理制度创新

目录 华为崛起两大因素&#xff1a;管理制度创新和组织文化。 管理是科学&#xff0c;150年来管理史上最伟大的创新是流程 为什么要变革&#xff1f; 向世界标杆学习&#xff0c;是变革第一方法论 体系之一&#xff1a;华为的DSTE战略管理体系&#xff08;解决&#xff1a…...

MySQL 临时表:使用技巧与最佳实践

MySQL 临时表&#xff1a;使用技巧与最佳实践 引言 在数据库管理系统中&#xff0c;临时表是一种常见的数据结构&#xff0c;它允许用户存储临时数据&#xff0c;这些数据只在当前会话或事务中有效。MySQL 作为一种广泛使用的数据库管理系统&#xff0c;也提供了对临时表的支…...

华为云语音交互SIS的使用案例(文字转语音-详细教程)

文章目录 题记一 、语音交互服务&#xff08;Speech Interaction Service&#xff0c;简称SIS&#xff09;二、功能介绍1、实时语音识别2、一句话识别3、录音文件识别4、语音合成 三、约束与限制四、使用1、API2、SDK 五、项目集成1、引入pom依赖2、初始化 Client1&#xff09;…...