0


selenium+beautifulsoup数据爬取

准备工作

1、安装selenium


pip install selenium

2、安装浏览器driver(以Edge浏览器为例)

  • 打开edge浏览器,然后“帮助和反馈”->“关于Microsoft Edge”,查看浏览器版本,根据版本号下载driver

Micro.png

  • 打开网站url ,根据浏览器版本下载对应的driver

list.png

  • 将下载的driver解压后放在爬虫脚本同级目录下

目录.png

3、需要安装的其他库


# 网络连接的库

pip install requests

# 处理标签数据的库

pip install beautifulsoup4

# 处理excel写入的库

pip install xlwt

4、分析网页和信息处理逻辑

分析网页

要爬取的页面.png

  • 可以看到信息主要是五个查询字段,分别是招生单位、所在地、研究生院、自划线院校、博士点,和两个必选字段分别是专业门类和专业领域。必须选择专业门类和专业领域才能进行查询。

门类.png

  • 打开页面的检查页面,可以看到很多个jsp的请求,getMI.jsp是学科门类下拉列表的数据,getZy.jsp是专业领域下拉列表的数据,getSs.jsp是所在地的数据。

action.png

  • 同时,网页数据还进行了分页处理,所以在爬取数据的时候也需要考虑到这一点。

分页.png

处理思路

经过对网页的简单的分析,需要先选中“学科门类”和“专业领域”,然后点击“查询”按钮,最后不断点击下一页按钮来获取网页源代码,在通过beautifulsoup对网页源代码进行信息提取,最后将提取的信息写入excel。

编写代码

方法解析

getMajor()方法


def getMajor():

    url_1 = "https://yz.chsi.com.cn/zsml/pages/getMl.jsp"

    url_2 = "https://yz.chsi.com.cn/zsml/pages/getZy.jsp"

    headers = {

        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36',

        'Connection': 'close'}  # CLOSE: 在header中不使用持久连接

    # 查询期刊名称及其他信息

    print("------------开始爬取-----------")

    # response = requests.post(url, headers=headers, data=payload, cookies=cookie)

    response = requests.post(url_1, headers=headers)

    result = response.json()

    zyxw = {'mc':'专业学位','dm':'zyxw'}

    result.insert(0,zyxw)

    datas = []

    payload = {

        'mldm': '01'

    }

    for item in result:

        payload['mldm'] = item['dm']

        response = requests.post(url_2, headers=headers, data=payload)

        data = response.json()

        datas.append(data)

    return result,datas

第一项下拉项.png

  • 不同门类下的专业领域数据需要传入参数才能获取,这里需要传入的payload中‘mldm’属性,这项属性也就是门类数据中的‘dm’属性,所以我们这里根据门类数据中的‘dm’属性分别获取每个门类下的不同专业领域信息。

数据类型.png

find_page()方法


def find_page(data_first,data_second):

    options = webdriver.ChromeOptions()

    # 解决DevToolsActivePort文件不存在的报错

    options.add_argument('--no-sandbox')

    # 指定浏览器分辨率

    options.add_argument('window-size=1600x900')

    # 谷歌文档提到需要加上这个属性来规避bug

    options.add_argument('--disable-gpu')

    # 隐藏滚动条, 应对一些特殊页面

    options.add_argument('--hide-scrollbars')

    # 不加载图片, 提升速度

    options.add_argument('blink-settings=imagesEnabled=false')

    # 浏览器不提供可视化页面. linux下如果系统不支持可视化不加这条会启动失败

    options.add_argument('--headless')

    # 初始化一个driver,driver的路径选择的是相对路径,不行就写绝对路径

    # edge

    driver = webdriver.Edge()

    # chrome

    # driver = webdriver.Chrome()

  

    # 网页主页面请求路径

    url = "https://yz.chsi.com.cn/zsml/queryAction.do"

    driver.get(url)

  

    # 学科门类

    s1_len = len(data_first)

    print(s1_len)

    allData = []

    for i in range(s1_len+1):

        # 给出加载时间

        time.sleep(1)

        s1 = Select(driver.find_element_by_name("mldm"))

        if i == 0:

            continue

        s1.select_by_index(i)

        name_one = data_first[i-1]['mc']

        # 学科类别

        s2_len = len(data_second[i-1])

        print(s2_len)

        pageData = []

        name_list = data_second[i-1]

        for j in range(s2_len+1):

            s2 = Select(driver.find_element_by_name("yjxkdm"))

            if j == 0:

                continue

            s2.select_by_index(j)

            print(i,j)

            name_two = data_second[i-1][j-1]['mc']

            # 查询按钮

            s3 = driver.find_element_by_name("button")

            s3.click()

            tablename = name_one + '-' + name_two

            print(tablename)

            pages = []

            # 跳页

            for l in range(50):

                currentPage = driver.page_source

                pages.append(currentPage)

                # 下一页

                s4 = driver.find_elements_by_class_name("lip")

                # 是否存在box直接跳页

                s5 = driver.find_elements_by_class_name("lip-input-box")

                time.sleep(1)

                if len(s5) == 0:

                    s4[-1].click()

                else:

                    s4[-2].click()

                nextPage = driver.page_source

                # 当前页和下一页一致跳出循环

                if nextPage == currentPage:

                    break

            pageData.append(pages)

        allData.append(pageData)

    # 将html交给beautifulsoup,每个大类

    getPage(allData,data_first,data_second)

  

    # 退出浏览器

    driver.close()

    driver.quit()
  • 这个方法主要是通过selenium库模拟网页的操作,获取网页源代码然后将这些网页源代码交给beautifulsoup库处理,从而提取数据。

  • 首先,我们查看网页源代码,发现两个下拉选择框的name属性分别是mldm和yjxkdm,查询按钮的name属性是button;获取这些元素对象进行模拟选择和查询。

源代码-1.png

  • 值得注意的点是这里遍历的遍历是从1开始且结束于len+1的,这是因为网页中下拉选项中的第一项是提示文字,并不能查询到实际的信息。

选择门类.png

  • 另一个值得注意的点是跳页的问题,我们找到下一页的按钮,对它进行模拟点击,这里我们循环了50次,这里为什么是50次?因为每页有30条数据,所以总体的数据大概有1500,而全国招收硕士的院校有863个,所以这个冗余是完全足够的。

研究生招生高校.png

  • 跳出循环的语句如下,逻辑是“当前页和下一页一致跳出循环”就说明已经到最后一页啦,就跳出循环,避免无效点击。

# 当前页和下一页一致跳出循环

if nextPage == currentPage:

    break

getPage()方法


# name_one为表名,name_two为子表名

def getPage(allData,data_first,data_second):

    all_data = []

    t = -1

    for pageData in allData:

        t = t + 1

        l = -1

        for pages in pageData:

            l = l + 1

            for page in pages:

                # 解析源代码

                soup = BeautifulSoup(page, 'html.parser')

                tbody = soup.find('tbody')

                # print(tbody)

                for item in tbody.children:

                    if isinstance(item, bs4.element.Tag):

                        k = 0

                        tdItem = []

                        tdItem.append(data_first[t]['mc'])

                        tdItem.append(data_second[t][l]['dm']+data_second[t][l]['mc'])

                        for td in item.children:

                            if isinstance(td, bs4.element.Tag):

                                if k == 0 or k == 1:

                                    s = td.text.replace("\n","")

                                    tdItem.append(s)

                                else:

                                    ii = td.find('i')

                                    if ii:

                                        tdItem.append('√')

                                    else:

                                        tdItem.append('×')

                                k = k + 1

                        all_data.append(tdItem)

    write_excel(all_data)
  • 这个方法是将获取的所有源代码交给beautifulsoup进行处理,获取我们需要的信息。

  • 下面的图是部分源码的信息,可以看到所有信息都在tbody标签下的tr标签下,对于前两项(招生单位和所在地)自己获取标签的文本信息,对于后三项我们采用找“i”标签的方式来获取信息,如果存在“i”标签,我们标记信息为“√”,否则标记为“错”。

源码-2.png

  • 此外,还需要将选择的属性值拼接到数据中,以实现较好地写入excel中。

tdItem.append(data_first[t]['mc'])

tdItem.append(data_second[t][l]['dm']+data_second[t][l]['mc'])

write_excel()方法


def write_excel(datas):

    workbook = xlwt.Workbook(encoding='utf-8')

    booksheet = workbook.add_sheet("学科门类", cell_overwrite_ok=False)

    # 添加表头

    booksheet.write(0, 0, "学科门类")

    booksheet.write(0, 1, "学科专业")

    booksheet.write(0, 2, "招生单位")

    booksheet.write(0, 3, "所在地")

    booksheet.write(0, 4, "是否有研究生院")

    booksheet.write(0, 5, "是否是自划线院校")

    booksheet.write(0, 6, "是否有博士点")

    for i, row in enumerate(datas):

        for j, col in enumerate(row):

            booksheet.write(i + 1, j, col)

    workbook.save('E:\\dataSet\\' + "数据" + '.xls')
  • 这个方法比较简单,将获取到的数据写入excel中,先写表头信息,然后写入数据,保存到excel里面

全代码展示

1、根据专业门类和专业领域写入多个excel文件


#!/opt/python39/bin/python3

# encoding=utf-8

import time

from selenium import webdriver

import xlwt

from bs4 import BeautifulSoup

import bs4

import requests

# 创建chrome参数对象

from selenium.webdriver.support.select import Select

def find_page(data_first,data_second):

    options = webdriver.ChromeOptions()

    # 解决DevToolsActivePort文件不存在的报错

    options.add_argument('--no-sandbox')

    # 指定浏览器分辨率

    options.add_argument('window-size=1600x900')

    # 谷歌文档提到需要加上这个属性来规避bug

    options.add_argument('--disable-gpu')

    # 隐藏滚动条, 应对一些特殊页面

    options.add_argument('--hide-scrollbars')

    # 不加载图片, 提升速度

    options.add_argument('blink-settings=imagesEnabled=false')

    # 浏览器不提供可视化页面. linux下如果系统不支持可视化不加这条会启动失败

    options.add_argument('--headless')

    # 初始化一个driver,driver的路径选择的是相对路径,不行就写绝对路径

    # edge

    driver = webdriver.Edge()

    # chrome

    # driver = webdriver.Chrome()

  

    # 网页主页面请求路径

    url = "https://yz.chsi.com.cn/zsml/queryAction.do"

    driver.get(url)

  

    # 学科门类

    s1_len = len(data_first)

    print(s1_len)

    for i in range(s1_len+1):

        # 给出加载时间

        time.sleep(1)

        s1 = Select(driver.find_element_by_name("mldm"))

        if i <= 4:

            continue

        s1.select_by_index(i)

        name_one = data_first[i-1]['mc']

        # 学科类别

        s2_len = len(data_second[i-1])

        print(s2_len)

        pageData = []

        name_list = data_second[i-1]

        for j in range(s2_len+1):

            s2 = Select(driver.find_element_by_name("yjxkdm"))

            if j == 0:

                continue

            s2.select_by_index(j)

            print(i,j)

            name_two = data_second[i-1][j-1]['mc']

            # 查询按钮

            s3 = driver.find_element_by_name("button")

            s3.click()

            tablename = name_one + '-' + name_two

            print(tablename)

            pages = []

            # 跳页

            for l in range(50):

                currentPage = driver.page_source

                pages.append(currentPage)

                # 下一页

                s4 = driver.find_elements_by_class_name("lip")

                # 是否存在box直接跳页

                s5 = driver.find_elements_by_class_name("lip-input-box")

                time.sleep(1)

                if len(s5) == 0:

                    s4[-1].click()

                else:

                    s4[-2].click()

                nextPage = driver.page_source

                # 当前页和下一页一致跳出循环

                if nextPage == currentPage:

                    break

            pageData.append(pages)

        # 将html交给beautifulsoup,每个大类

        getPage(pageData,name_one,name_list)

  

    # 退出浏览器

    driver.close()

    driver.quit()

# name_one为表名,name_two为子表名

def getPage(pageData,name_one,name_list):

    datas = []

    for pages in pageData:

        data = []

        for page in pages:

            # 解析源代码

            soup = BeautifulSoup(page, 'html.parser')

            tbody = soup.find('tbody')

            # print(tbody)

            for item in tbody.children:

                if isinstance(item, bs4.element.Tag):

                    k = 0

                    tdItem = []

                    for td in item.children:

                        if isinstance(td, bs4.element.Tag):

                            if k == 0 or k == 1:

                                s = td.text.replace("\n","")

                                tdItem.append(s)

                            else:

                                ii = td.find('i')

                                if ii:

                                    tdItem.append('是')

                                else:

                                    tdItem.append('否')

                            k = k + 1

                    data.append(tdItem)

        print(data)

        datas.append(data)

    write_excel(datas,name_one,name_list)

def getMajor():

    url_1 = "https://yz.chsi.com.cn/zsml/pages/getMl.jsp"

    url_2 = "https://yz.chsi.com.cn/zsml/pages/getZy.jsp"

    headers = {

        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36',

        'Connection': 'close'}  # CLOSE: 在header中不使用持久连接

    # 查询期刊名称及其他信息

    print(":------------开始爬取-----------")

    # response = requests.post(url, headers=headers, data=payload, cookies=cookie)

    response = requests.post(url_1, headers=headers)

    result = response.json()

    zyxw = {'mc':'专业学位','dm':'zyxw'}

    result.insert(0,zyxw)

    datas = []

    payload = {

        'mldm': '01'

    }

    for item in result:

        payload['mldm'] = item['dm']

        response = requests.post(url_2, headers=headers, data=payload)

        data = response.json()

        datas.append(data)

    return result,datas

def write_excel(datas,name_one,name_list):

    workbook = xlwt.Workbook(encoding='utf-8')

    k = 0

    print(datas)

    for item in name_list:

        name = item['mc']

        dm = item['dm']

        if name == '':

            name = dm

        # 写入为excel文件

        booksheet = workbook.add_sheet(name, cell_overwrite_ok=False)

        # 添加表头

        booksheet.write(0, 0, "招生单位")

        booksheet.write(0, 1, "所在地")

        booksheet.write(0, 2, "是否有研究生院")

        booksheet.write(0, 3, "是否是自划线院校")

        booksheet.write(0, 4, "是否有博士点")

        for i, row in enumerate(datas[k]):

            for j, col in enumerate(row):

                booksheet.write(i + 1, j, col)

        # 第k个数据

        k = k+1

    workbook.save('E:\\dataSet\\' + name_one + '.xls')

data_first,data_second = getMajor()

find_page(data_first,data_second)

2、将所有数据写入同一个excel文件


#!/opt/python39/bin/python3

# encoding=utf-8

import time

from selenium import webdriver

import xlwt

from bs4 import BeautifulSoup

import bs4

import requests

# 创建chrome参数对象

from selenium.webdriver.support.select import Select

def find_page(data_first,data_second):

    options = webdriver.ChromeOptions()

    # 解决DevToolsActivePort文件不存在的报错

    options.add_argument('--no-sandbox')

    # 指定浏览器分辨率

    options.add_argument('window-size=1600x900')

    # 谷歌文档提到需要加上这个属性来规避bug

    options.add_argument('--disable-gpu')

    # 隐藏滚动条, 应对一些特殊页面

    options.add_argument('--hide-scrollbars')

    # 不加载图片, 提升速度

    options.add_argument('blink-settings=imagesEnabled=false')

    # 浏览器不提供可视化页面. linux下如果系统不支持可视化不加这条会启动失败

    options.add_argument('--headless')

    # 初始化一个driver,driver的路径选择的是相对路径,不行就写绝对路径

    # edge

    driver = webdriver.Edge()

    # chrome

    # driver = webdriver.Chrome()

  

    # 网页主页面请求路径

    url = "https://yz.chsi.com.cn/zsml/queryAction.do"

    driver.get(url)

  

    # 学科门类

    s1_len = len(data_first)

    print(s1_len)

    allData = []

    for i in range(s1_len+1):

        # 给出加载时间

        time.sleep(1)

        s1 = Select(driver.find_element_by_name("mldm"))

        if i == 0:

            continue

        s1.select_by_index(i)

        name_one = data_first[i-1]['mc']

        # 学科类别

        s2_len = len(data_second[i-1])

        print(s2_len)

        pageData = []

        name_list = data_second[i-1]

        for j in range(s2_len+1):

            s2 = Select(driver.find_element_by_name("yjxkdm"))

            if j == 0:

                continue

            s2.select_by_index(j)

            print(i,j)

            name_two = data_second[i-1][j-1]['mc']

            # 查询按钮

            s3 = driver.find_element_by_name("button")

            s3.click()

            tablename = name_one + '-' + name_two

            print(tablename)

            pages = []

            # 跳页

            for l in range(50):

                currentPage = driver.page_source

                pages.append(currentPage)

                # 下一页

                s4 = driver.find_elements_by_class_name("lip")

                # 是否存在box直接跳页

                s5 = driver.find_elements_by_class_name("lip-input-box")

                time.sleep(1)

                if len(s5) == 0:

                    s4[-1].click()

                else:

                    s4[-2].click()

                nextPage = driver.page_source

                # 当前页和下一页一致跳出循环

                if nextPage == currentPage:

                    break

            pageData.append(pages)

        allData.append(pageData)

        # 将html交给beautifulsoup,每个大类

    getPage(allData,data_first,data_second)

  

    # 退出浏览器

    driver.close()

    driver.quit()

# name_one为表名,name_two为子表名

def getPage(allData,data_first,data_second):

    all_data = []

    t = -1

    for pageData in allData:

        t = t + 1

        l = -1

        for pages in pageData:

            l = l + 1

            for page in pages:

                # 解析源代码

                soup = BeautifulSoup(page, 'html.parser')

                tbody = soup.find('tbody')

                # print(tbody)

                for item in tbody.children:

                    if isinstance(item, bs4.element.Tag):

                        k = 0

                        tdItem = []

                        tdItem.append(data_first[t]['mc'])

                        tdItem.append(data_second[t][l]['dm']+data_second[t][l]['mc'])

                        for td in item.children:

                            if isinstance(td, bs4.element.Tag):

                                if k == 0 or k == 1:

                                    s = td.text.replace("\n","")

                                    tdItem.append(s)

                                else:

                                    ii = td.find('i')

                                    if ii:

                                        tdItem.append('√')

                                    else:

                                        tdItem.append('×')

                                k = k + 1

                        all_data.append(tdItem)

    write_excel(all_data)

def getMajor():

    url_1 = "https://yz.chsi.com.cn/zsml/pages/getMl.jsp"

    url_2 = "https://yz.chsi.com.cn/zsml/pages/getZy.jsp"

    headers = {

        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.0.0 Safari/537.36',

        'Connection': 'close'}  # CLOSE: 在header中不使用持久连接

    # 查询期刊名称及其他信息

    print("------------开始爬取-----------")

    # response = requests.post(url, headers=headers, data=payload, cookies=cookie)

    response = requests.post(url_1, headers=headers)

    result = response.json()

    zyxw = {'mc':'专业学位','dm':'zyxw'}

    result.insert(0,zyxw)

    datas = []

    payload = {

        'mldm': '01'

    }

    for item in result:

        payload['mldm'] = item['dm']

        response = requests.post(url_2, headers=headers, data=payload)

        data = response.json()

        datas.append(data)

    return result,datas

def write_excel(datas):

    workbook = xlwt.Workbook(encoding='utf-8')

    booksheet = workbook.add_sheet("学科门类", cell_overwrite_ok=False)

    # 添加表头

    booksheet.write(0, 0, "学科门类")

    booksheet.write(0, 1, "学科专业")

    booksheet.write(0, 2, "招生单位")

    booksheet.write(0, 3, "所在地")

    booksheet.write(0, 4, "是否有研究生院")

    booksheet.write(0, 5, "是否是自划线院校")

    booksheet.write(0, 6, "是否有博士点")

    for i, row in enumerate(datas):

        for j, col in enumerate(row):

            booksheet.write(i + 1, j, col)

    workbook.save('E:\\dataSet\\' + "数据" + '.xls')

data_first,data_second = getMajor()

print(data_first)

print(data_second)

find_page(data_first,data_second)

结果

one.png

生成一个表的结果:

一个表结果.png

生成多个表的结果:

多个表的结果.png

标签: selenium python 爬虫

本文转载自: https://blog.csdn.net/qq_42281116/article/details/125428304
版权归原作者 弹一个吐司 所有, 如有侵权,请联系我们删除。

“selenium+beautifulsoup数据爬取”的评论:

还没有评论