【案例】python数据分析案例分享

   日期:2020-10-01     浏览:91    评论:0    
核心提示:数据来源:[中国审判流程信息公开网](https://splcgk.court.gov.cn/gzfwww/)写在前面的话:切记切记要设置休眠,不能无休止访问,网站也有封禁IP的措施,访问过于频繁会被封IP

写在前面的话:切记切记要设置休眠,不能频繁请求

小白的一点案例记录,望大神们手下留情。。。
共两部分源码分别见3.1和3.2

一、背景前提

日常辛苦工(mo)作(yu)之后的某时,心血来潮想查下以前离职公司现在怎么样了,于是各种企业信息查询,某查查登场,注册–>验证–>绑定–>登录,还好可以看了,猛然眼前一亮,诉讼异常,悲(窃)伤(喜)着点开,会员,看不到全部内容,咱也理解,毕竟人家是公司不是盈利机构,于是乎,就有了本文的初始念头:我自己取数据自己查找自己分析!

二、准备工作

再叨叨一句:小心,爬着爬着就进去了!
用selenium模拟比较真实一些,慢就慢点无所谓
环境:win10、python3.7
工具:anaconda spyder、chrome driver
三方包:selenium、pandas、bs4、requests、random

三、数据采集及清洗

分析了下网站结构,
1、首页的搜索按钮必须输入关键词才能搜索,不同关键词的搜索结果数量不一;
2、搜索“0”出现的案例条数,与首页下方的案例点击后相加得到的条数一致;
3、列表页的标题行固定为class="fd-list-01"
4、标题页没有进入详情页的连接;且点击标题后,新窗口打开详情页;
5、打开详情页后发现,详情页连接较统一,拼接变量为文章类型和文章ID;
6、列表页标题中的onclick即有此两个变量;
7、测试验证上述5和6成功;
8、凑个数吧;

1.目录采集

先上源码:

# -*- coding: utf-8 -*-
""" Created on Thu Sep 24 16:52:53 2020 @author: janlyn """

from selenium import webdriver
import time
import pandas as pd
import random

driver = webdriver.Chrome()

driver.get(图片)
driver.find_element_by_id('fd-search').send_keys('0')
driver.find_element_by_class_name('fd-btn').click()
driver.switch_to.window(driver.window_handles[1])


# 获取列表页信息
def get_data():
    items = driver.find_elements_by_class_name('fd-list-01')
    for ele in items[1:]:
        titles = ele.text
        a = ele.find_element_by_tag_name('a')
        # 获取onlick中的内容
        alls = a.get_attribute('onclick')
        if alls:
            # 提取onlick中的内容,完整内容为
            # οnclick="ckxq('开庭公告','D5EA00BE1700316F2AA7B7C5EEF535F5')"
            li = alls.replace("ckxq('","").replace("')","").split("','")
            li.append(titles)
            al.append(li)
            

# 点击下一页
def click_next():
    pages = driver.find_element_by_class_name('pageBtnWrap').find_elements_by_tag_name('a')
    for page in pages:
        title = page.get_attribute('title')
        if title == '下一页':
            page.click()
            

# 若失败则重新执行当前页
def loop_temp(func,page):
    reg = 1
    while reg == 1:
        try:
            func
            reg = 0
            print('{}执行成功'.format(page))
        except:
            print('{}执行失败,再来一次'.format(page))
            reg = 1

# 字段头,type和id需要构造详情页url,title只是顺手取出来,方便验证
al = [['type','id','title']]

# 循环遍历全部页数
for i in range(1,28):
    loop_temp(get_data(),i)
    reg = 1
    # 判断获取的数据是否为当前遍历页数据
    while reg == 1:
        loop_temp(click_next(),i)
        time.sleep(random.randrange(50,150,10)/100)
        curr = driver.find_element_by_class_name('curr').text
        if curr == str(i+1):
            reg = 0
# 最后一页直接获取数据
get_data()

# 转为df数据框,方便操作
df_te = pd.DataFrame(te[1:],columns=te[0])
# 去重数据
df_te_tmp = df_te.drop_duplicates()
# 保存列表数据
df_te_tmp.to_excel('spyder.xlsx',index=False)


直接保存运行肯定会出错滴,你得调试呐,这又不是成品源码;
思路如下:

1.0实例化浏览器

driver = webdriver.Chrome()

1.1打开网站

.get()方法打开链接

driver.get(图片)

1.2输入关键词

.send_keys()方法输入内容

driver.find_element_by_id('fd-search').send_keys('0')

1.3点击检索

.click()方法进行点击

driver.find_element_by_class_name('fd-btn').click()

1.4切换窗口

可以通过driver.title查看当前tab标题
可以通过driver.refresh()刷新当前tab
driver.window_handles获取tab句柄
.switch_to.window()根据句柄进行切换

driver.switch_to.window(driver.window_handles[1])

1.5获取列表页数据

.get_attribute()可获取当前元素中的指定属性值,前文述的类型和id均可在’onlick’中进行获取

# 获取列表页信息
def get_data():
    items = driver.find_elements_by_class_name('fd-list-01')
    for ele in items[1:]:
        titles = ele.text
        a = ele.find_element_by_tag_name('a')
        # 获取onlick中的内容
        alls = a.get_attribute('onclick')
        if alls:
            # 提取onlick中的内容,完整内容为
            # οnclick="ckxq('开庭公告','D5EA00BE1700316F2AA7B7C5EEF535F5')"
            li = alls.replace("ckxq('","").replace("')","").split("','")
            li.append(titles)
            al.append(li)

1.6点击下一页

循环classpageBtnWrapa标签,并判断title的值是否为下一页,若是则点击

# 点击下一页
def click_next():
    pages = driver.find_element_by_class_name('pageBtnWrap').find_elements_by_tag_name('a')
    for page in pages:
        title = page.get_attribute('title')
        if title == '下一页':
            page.click()

1.7列表页结束

点击下一页或获取列表页失败时,需要重新尝试

# 若失败则重新执行当前页
def loop_temp(func,page):
    reg = 1
    while reg == 1:
        try:
            func
            reg = 0
            print('{}执行成功'.format(page))
        except:
            print('{}执行失败,再来一次'.format(page))
            reg = 1

已知失败原因如下:
1)点击下一页后实际未点击(可能页面未加载完成导致),导致重复采集;
2)点击下一页后,页面未加载完毕,导致页面属性缺失,从而获取不到列表页相关信息;
3)点击过快导致页面加载失败;

pd可以直接将二维数组转化为数据框,故将提取的数据存为列表,先上字段表头

# 字段头,type和id需要构造详情页url,title只是顺手取出来,方便验证
al = [['type','id','title']]

并循环遍历每一页进行采集
最后一页时多调用一次列表数据,而不需要进入循环

# 循环遍历全部页数
for i in range(1,28):
    loop_temp(get_data(),i)
    reg = 1
    # 判断获取的数据是否为当前遍历页数据
    while reg == 1:
        loop_temp(click_next(),i)
        time.sleep(random.randrange(50,150,10)/100)
        curr = driver.find_element_by_class_name('curr').text
        if curr == str(i+1):
            reg = 0
# 最后一页直接获取数据
get_data()
# 转为df数据框,方便操作
df_te = pd.DataFrame(te[1:],columns=te[0])
# 去重数据
df_te_tmp = df_te.drop_duplicates()
# 保存列表数据,到当前工作目录下
df_te_tmp.to_excel('spyder.xlsx',index=False)

2.详情页采集

上源码

在这里插入代码片

2.1读取列表页采集结果

detail = pd.read_excel('spyder.xlsx')

2.2构造url

type_dic = { 图片}
url = type_dic[detail_type]
url = '{}?id={}'.format(url,detail_id)

2.3请求链接并清洗数据

2.3.1方法一:requests模拟请求头获取(不推荐)

此处有个工具,详见:curl转python

def get_detail_spyder(detail_type = '案例',detail_id = 'ff8080815a5ef25f015a7407287c1b3a',title='列表标题'):
    # BeautifulSoup 解析
    headers = { 
        'Connection': 'keep-alive',
        'Cache-Control': 'max-age=0',
        'Upgrade-Insecure-Requests': '1',
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.89 Safari/537.36',
        'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9',
        'Sec-Fetch-Site': 'same-origin',
        'Sec-Fetch-Mode': 'navigate',
        'Sec-Fetch-User': '?1',
        'Sec-Fetch-Dest': 'document',
        'Referer': 图片,
        'Accept-Language': 'zh-CN,zh;q=0.9',
    }
    # params = (('id', detail_id),)
    url = type_dic[detail_type]
    url = '{}?id={}'.format(url,detail_id)
    try:
        # 随机休眠0.5-1.5秒
        time.sleep(random.randrange(50,150,10)/100)
        # response = requests.get(url, headers=headers, params=params)
        response = requests.get(url, headers=headers)
        bsobj = BeautifulSoup(response.text,'lxml')
        # 标题正文等合体
        bs_all = bsobj.find(attrs={ "class":"fd-fix"})
        # 文章标题
        title_name = bs_all.findChild().text
        # 文章标题下方的文章信息,待解析
        title_info = bs_all.findChild().findNext().text
        fabudanwei,suoshushengfen,fabushijian,liulanliang=('','','','')
        # 有的文章无该4个字段中的某个,故循环遍历匹配提取
        for i in title_info.split('\u3000\u3000'):
            if '发布单位' in i:
                fabudanwei = i.split(':')[1]
            elif '所属省份' in i:
                suoshushengfen = i.split(':')[1]
            elif '发布时间' in i:
                fabushijian = i.split(':')[1]
            elif '浏览量' in i:
                liulanliang = i.split(':')[1]
        zhengwen_html = str(bs_all.find(attrs={ "class":"fd-alt-all"}))
        # 清除style标签
        [s.extract() for s in bs_all("style")]  
        zhengwen = bs_all.find(attrs={ "class":"fd-alt-all"}).text
        # 构造并返回字典
        dic = { '类型':detail_type,'标题':title_name,'列表标题':title,'信息':title_info,\
               '发布单位':fabudanwei,'所属省份':suoshushengfen,'发布时间':fabushijian,\
               '浏览量':liulanliang,'正文html':zhengwen_html,'正文':zhengwen,'url':url}
        return dic
    except Exception as e:
        print(url,e)
        return 0

2.3.2方法二:selenium模拟浏览器(推荐)

def get_detail(driver,detail_type = '案例',detail_id = 'ff8080815a5ef25f015a7407287c1b3a',title='列表标题'):
    # selenium解析
    url = type_dic[detail_type]
    url = '{}?id={}'.format(url,detail_id)
    driver.get(url)
    # 随机休眠0.5-1.5秒
    time.sleep(random.randrange(50,150,10)/100)
    try:
        # 标题正文等合体
        bs_all = driver.find_element_by_class_name('fd-fix')
        # 文章标题
        title_name = bs_all.find_element_by_tag_name('h2').text
        # 文章标题下方的文章信息,待解析
        title_info = bs_all.find_element_by_tag_name('h5').text
        fabudanwei,suoshushengfen,fabushijian,liulanliang=('','','','')
        # 有的文章无该4个字段中的某个,故循环遍历匹配提取
        for i in title_info.split('\u3000\u3000'):
            if '发布单位' in i:
                fabudanwei = i.split(':')[1]
            elif '所属省份' in i:
                suoshushengfen = i.split(':')[1]
            elif '发布时间' in i:
                fabushijian = i.split(':')[1]
            elif '浏览量' in i:
                liulanliang = i.split(':')[1]
        zhengwen_html = bs_all.find_element_by_class_name('fd-alt-all').get_attribute('outerHTML')
        zhengwen = bs_all.find_element_by_class_name('fd-alt-all').text
        # 构造并返回字典
        dic = { '类型':detail_type,'标题':title_name,'列表标题':title,'信息':title_info,\
               '发布单位':fabudanwei,'所属省份':suoshushengfen,'发布时间':fabushijian,\
               '浏览量':liulanliang,'正文html':zhengwen_html,'正文':zhengwen,'url':url}
        return dic
    except Exception as e:
        print(url,e)
        return 0

2.4自主选择方法一或方法二

leixing = 2
if leixing == 2:
    driver = webdriver.Chrome()
for index,detail_type,detail_id,title,url in detail.itertuples():
    print('正在获取第{}条数据...,连接:{}'.format(index+1,url))
    while True:
        if leixing == 1:
            dic = get_detail_spyder(detail_type,detail_id,title)
        elif leixing == 2:
            dic = get_detail(driver,detail_type,detail_id,title)
        if dic:
            result_list.append(dic)
            break

result_df = pd.DataFrame(result_list)

四、数据分析

见下篇

 
打赏
 本文转载自:网络 
所有权利归属于原作者,如文章来源标示错误或侵犯了您的权利请联系微信13520258486
更多>最近资讯中心
更多>最新资讯中心
0相关评论

推荐图文
推荐资讯中心
点击排行
最新信息
新手指南
采购商服务
供应商服务
交易安全
关注我们
手机网站:
新浪微博:
微信关注:

13520258486

周一至周五 9:00-18:00
(其他时间联系在线客服)

24小时在线客服