Python自学第6周反馈:爬取某城市企业黄页信息(1)-- --分析该地区产业结构

为了知道在某个城市什么行业比较好做,所以这里的目标时对某黄页网站的信息进行爬取,获得在录的企业数据,用来反应当地的产业结构

目标:抓取各行各业的企业数量(在录)
来源:某企业黄页网站
步骤1:解析URL
步骤2:编写爬取代码
步骤3:导出信息并简单分析
备注:文末会分享本次自学过程中的完整代码内容,
下一篇博客将会分享爬取某城市行业在录公司的信息(公司名、法人、注册时间、产品、联系方式等)

零、 首先,写一个工具:
用来重复尝试请求url中特定元素的信息(含注释解析)

from retrying import retry                                 #从retrying库中导入retry模块,获取网页时连接超时重复尝试
@retry(stop_max_attempt_number=10)                          #设置最大尝试次数
def huoqu(url,yuansu,time_out):                            #写一个获取网页中关键信息的函数huoqu(获取)
    try:                                                   #如果失败,重复尝试以下程序
        from urllib import request                         #从urllib库中导入request模块
                                                           #编写请求头User-Agent,用来避免一些反爬,可以从自己的后台获取
        qingqiutou_UA = {'User-Agent': 'Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN;rv:1.8.1.14) Gecko/20080404 Firefox/2.0.0.14'}
        URL = request.Request(url, headers=qingqiutou_UA)  #对url装载请求头User-Agent
        shuju_1 = request.urlopen(URL, timeout=time_out)   #把URL请求到的数据装入一个变量shuju_1中,设置请求时长timeout,超时就会进行重新尝试
        shuju_2 = shuju_1.readlines()                      #把得到的数据按行读取成行数据列表,装进新变量shuju_2
        guodu = []                                         #设置一个过渡列表
        for a in shuju_2:                                  #遍历shuju_2内的行数据列表
            if yuansu in a.decode('utf-8').strip():        #如果行数据列表中的元素进行utf-8解码后包含指定的信息元素(yuansu)
                guodu.append(a.decode('utf-8').strip())    #就把这个解码后的元素用strip()函数排除前后空白后放入过渡列表
        if len(guodu) <= 1:                                #判断过渡列表中含有的元素个数是否小于等于1
            for i in guodu:                                #如果是,说明只有小于一行符合要求,那么单独抽出这个元素
                shuju_3 = i                                #把这个元素给新变量shuju_3
        else:                                              #如果不是,过渡列表含有多个符合元素
            shuju_3 = guodu                                #则让新变量shuju_3等于这个过渡列表
    except:                                                #如果反复尝试5次之后仍然连接超时
        shuju_3 = ''                                       #则让新变量shuju_3等于空值''
    return shuju_3                                         #对调用函数huoqu返回shuju_3(可能是单个字符串,也可能是列表或者None)

一、 解析URL首页:
Python自学第6周反馈:爬取某城市企业黄页信息(1)-- --分析该地区产业结构_第1张图片
这个页面的源码中含有所有下级页面的URL,只需要调用上面写好的获取函数,对这个页面的特定信息进行提取,即可获得装有所有下级URL 的列表

url = 'http://b2b.huangye88.com/huizhou/'                  #目标网址是某黄页网站某地区的‘首页’,从这个网址获取其他下级页面的URL
url_1 = huoqu(url,'.com',30)                               #调用获取函数,对‘首页’获取其中包括'.com'元素即为网址的行信息,设置时间为30S
url_2 = []                                                 #建立一个空白的列表url_2
for a in url_1:                                            #遍历得到的含有下级url的列表
    if '名录">惠州' in a:                                  #通过查看网页源码可以发现下级网页所在都包含有'名录">惠州',通过这个成分对信息进行一次过滤
        url_2.append(a)                                    #过滤后放入准备好的列表url_2
url_3 = []                                                 #建立一个空白的列表url_3
for b in url_2:                                            #遍历上一次过滤后得到的列表
    C = re.split(r'"',b)                                   #对列表元素进行切割,所有的下级url都用"双引号括起来,用split()在"所在地方切割获得单独的url
    for c in C:                                            #从这种切割后获得的列表中遍历
        if '.com' in c:                                    #如果含有 '.com'即为url,提取出来
            url_3.append(c)                                #放入准备好的列表url_3

二、 对得到的二级URL列表发送请求获取主要信息
Python自学第6周反馈:爬取某城市企业黄页信息(1)-- --分析该地区产业结构_第2张图片

<span style="float:right;padding-right:10px">惠州机械名录共收录<em>1459</em>个惠州机械公司资料</span>

可以看到:
“>” 符号之间:
包括了收录个数 “1459” ,和行业词条 “个惠州机械公司资料”

其中:
“个惠州机械公司资料” 的行业名:“机械” 被包含在 “惠州”“公司” 之间

所以:
1.用写好的获取函数,单独获取含有‘共收录’元素的行信息;
2.并按照符号 “>” 用re库下的split()函数进行切割,指定位置即为收录数量
3.再对 “个惠州机械公司资料” 按照 “惠州”“公司” 进行切割,获得指定位置的行业名称
4.排列装载进字典中即可输出

Xinxi = []                                                 #建立一个空白的列表Xinxi用来放信息
for d in list(range(1,len(url_3)+1)):                      #建立一个列表用来表示url_3的序数并遍历这个序数列表
    url_4 = url_3[d-1]                                     #把url_3指定位置的元素给变量url_4(这里是循环放入url字符串)
    xinxi = huoqu(url_4, '共收录', 30)                     #目标是找到某城市某行业收录了多少条公司信息,所以依据源码,对'共收录'调用获取函数
    Xinxi.append(xinxi)                                    #把获取的信息xinxi放入专门的列表Xinxi中
                                                           # 这一步用来显示系统循环的进程
    sys.stdout.write('\r[ === [%d/%d] %d%% === ]' % ((d), len(url_3), int((d) /len(url_3) * 100)))
xinxi = {}                                                 #准备一个空字典xinxi,这里的信息个循环内的xinxi不一致不影响
for e in range(0,len(Xinxi)):                              #建立一个列表用来表示Xxinxi的序数并遍历这个序数列表
    E = re.split(r'>|,str(Xinxi[e]))                    #对遍历到的序数位置的元素进行切割,解析源码后知道主要信息被包括在>,
    #print(E)
    xinxi['第'+str(e+1)+'行'] = {}                         #每个行业建立一个行键,显示为第几行数据
    jian = re.split(r'惠州|公司',str(E[2]))                #对切割后的E列表中的第三个元素按照惠州,公司两个进行再切割,得到的新列表第二个元素包含了行业名称
    #print(jian)
    xinxi['第'+str(e+1)+'行']['第'+str(1)+'列']=str(jian[1])#把行业名称放到当行第一列
    xinxi['第'+str(e+1)+'行']['第'+str(2)+'列'] = int(E[6])#把E列表中第7个元素即收录数量放入当行第二列
for a,b in xinxi.items():                                  #遍历一下这个xinxi列表查看下信息是否正确
    print(a,b)

最受显示出来的效果即为:

1{'第1列': '机械', '第2列': 1459}2{'第1列': '机床', '第2列': 760}3{'第1列': '电子', '第2列': 731}4{'第1列': '五金', '第2列': 684}5{'第1列': '灯饰', '第2列': 597}6{'第1列': '电气', '第2列': 455}7{'第1列': '印刷', '第2列': 328}8{'第1列': '纸业', '第2列': 285}9{'第1列': '环保', '第2列': 186}10{'第1列': '汽配', '第2列': 175}11{'第1列': '丝印特印', '第2列': 140}12{'第1列': '过滤', '第2列': 138}13{'第1列': '泵阀', '第2列': 138}14{'第1列': '安防', '第2列': 128}15{'第1列': '加工', '第2列': 125}16{'第1列': '通信', '第2列': 116}17{'第1列': '汽修', '第2列': 114}18{'第1列': 'LED', '第2列': 85}19{'第1列': '汽车用品', '第2列': 83}20{'第1列': '仪器仪表', '第2列': 84}21{'第1列': '包装', '第2列': 84}22{'第1列': '汽车', '第2列': 73}23{'第1列': '工程机械', '第2列': 71}24{'第1列': '消防', '第2列': 65}25{'第1列': '水工业', '第2列': 52}26{'第1列': '纸管', '第2列': 42}27{'第1列': '添加剂', '第2列': 37}28{'第1列': '焊接切割', '第2列': 35}29{'第1列': '二手设备', '第2列': 27}30{'第1列': '耐火材料', '第2列': 24}31{'第1列': '暖通空调', '第2列': 23}32{'第1列': '太阳能', '第2列': 22}33{'第1列': '广电', '第2列': 19}34{'第1列': '物流设备', '第2列': 17}35{'第1列': '热泵', '第2列': 16}36{'第1列': '工控', '第2列': 12}37{'第1列': 'IT', '第2列': 1167}38{'第1列': '家电', '第2列': 605}39{'第1列': '礼品', '第2列': 402}40{'第1列': '家居', '第2列': 389}41{'第1列': '运动休闲', '第2列': 281}42{'第1列': '家具', '第2列': 265}43{'第1列': '办公', '第2列': 248}44{'第1列': '制鞋', '第2列': 234}45{'第1列': '酒店', '第2列': 226}46{'第1列': '美容美发', '第2列': 206}47{'第1列': '音响灯光', '第2列': 185}48{'第1列': '教育装备', '第2列': 125}49{'第1列': '玩具', '第2列': 116}50{'第1列': '服饰', '第2列': 95}51{'第1列': '皮具', '第2列': 86}52{'第1列': '服装', '第2列': 84}53{'第1列': '珠宝', '第2列': 49}54{'第1列': '小家电', '第2列': 44}55{'第1列': '影音', '第2列': 39}56{'第1列': '二手', '第2列': 31}57{'第1列': '智能', '第2列': 30}58{'第1列': '古玩', '第2列': 29}59{'第1列': '零食', '第2列': 25}60{'第1列': '宠物', '第2列': 25}61{'第1列': '母婴', '第2列': 7}62{'第1列': '商务服务', '第2列': 865}63{'第1列': '教育', '第2列': 581}64{'第1列': '生活服务', '第2列': 518}65{'第1列': '广告', '第2列': 263}66{'第1列': '物流', '第2列': 188}67{'第1列': '交通运输', '第2列': 184}68{'第1列': '网站建设', '第2列': 134}69{'第1列': '创业', '第2列': 83}70{'第1列': '维修', '第2列': 75}71{'第1列': '项目', '第2列': 54}72{'第1列': '展会', '第2列': 37}73{'第1列': '船舶', '第2列': 14}74{'第1列': '建材', '第2列': 761}75{'第1列': '纺织', '第2列': 354}76{'第1列': '能源', '第2列': 354}77{'第1列': '化工', '第2列': 323}78{'第1列': '表面处理', '第2列': 300}79{'第1列': '冶金', '第2列': 264}80{'第1列': '房地产', '第2列': 148}81{'第1列': '塑料', '第2列': 112}82{'第1列': '皮革', '第2列': 76}83{'第1列': '超硬材料', '第2列': 69}84{'第1列': '橡胶', '第2列': 56}85{'第1列': '涂料', '第2列': 51}86{'第1列': '石油', '第2列': 35}87{'第1列': '石材', '第2列': 34}88{'第1列': '钢铁', '第2列': 30}89{'第1列': '陶瓷', '第2列': 13}90{'第1列': '卫浴', '第2列': 12}91{'第1列': '食品', '第2列': 103}92{'第1列': '水果批发', '第2列': 102}93{'第1列': '养殖', '第2列': 88}94{'第1列': '食品机械', '第2列': 72}95{'第1列': '农机', '第2列': 29}96{'第1列': '园林', '第2列': 18}97{'第1列': '农化', '第2列': 6}

分享两个写好的工具函数用于导出标准字典(第几行第几列)数据:

#把表格字典转化成表格样式的一整个字符串 返回字符串
def write_excel(A):                                                                      #创建一个转换字典为特定字符表的函数
    for B,C in A.items():                                                                #遍历表字典内的行:列键值对
        Hang = int(len(A))                                                               #获得行数
        Lie  = int(len(C))                                                               #获得列数
        Lie_Biao = []                                                                    #创建中转列:值对的列表
        Zuizhong = []                                                                    #创建最终所有列值对字符串列表
        for hhh in A.values():                                                           #遍历表中的列字典
            for lll in hhh.values():                                                     #遍历列字典的值
                Lie_Biao.append(str(lll))                                                #把值字符串化添加到值列表
        for hangshu in range(0, Hang + 1):                                               #定义行数为跳转步长
            guodu = Lie_Biao[hangshu * Lie:hangshu * Lie + Lie]                          #定义按每行转化成过渡切片
            jiange_1 = '\t'                                                              #定义一个制表符
            meiyihang = jiange_1.join(guodu)                                             #用制表符来连接切片中的每一列
            Zuizhong.append(meiyihang)                                                   #把由每一列连起来的每一行添加到最终列表
        jiange_2 = '\n'                                                                  #定义一个换行符
        zhenggebiao = jiange_2.join(Zuizhong)                                            #用换行符来连接最终列表内每个行元素
        return zhenggebiao                                                               #返回一个表示整个表的字符串
#把特定的字符串写入特定路径按特定名和格式保存
def save_excel(baocunduixiang,wenjianjialujing,baocunming,geshihouzhui):
    baocunming = str(baocunming)                                                         #指定保存名
    LUJING_NEW = wenjianjialujing + '\\' + baocunming + '.'+ geshihouzhui                #拼装最终路径
    f = open(LUJING_NEW, 'w',encoding='utf-8')                                           # 在目的路径声明一个文件及格式并打开
    f.write(baocunduixiang)                                                              # 把处理好的信息写入这个文件
    f.close()                                                                            # 关闭写入操作

调用这两个工具函数对上面的数据进行保存即可:

qiye = write_excel(xinxi)
lujing = input("路径:")
baocun = input("保存文件名:")
save_excel(qiye,lujing,baocun,'xls')

得到的数据如图标所示:
Python自学第6周反馈:爬取某城市企业黄页信息(1)-- --分析该地区产业结构_第3张图片
Python自学第6周反馈:爬取某城市企业黄页信息(1)-- --分析该地区产业结构_第4张图片
这里分享下本次学习中的完整代码,如果抓取失败可能是因为超时导致没有信息可供切割导致的:

from retrying import retry                                 #从retrying库中导入retry模块,获取网页时连接超时重复尝试
@retry(stop_max_attempt_number=10)                          #设置最大尝试次数
def huoqu(url,yuansu,time_out):                            #写一个获取网页中关键信息的函数huoqu(获取)
    try:                                                   #如果失败,重复尝试以下程序
        from urllib import request                         #从urllib库中导入request模块
                                                           #编写请求头User-Agent,用来避免一些反爬,可以从自己的后台获取
        qingqiutou_UA = {'User-Agent': 'Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN;rv:1.8.1.14) Gecko/20080404 Firefox/2.0.0.14'}
        URL = request.Request(url, headers=qingqiutou_UA)  #对url装载请求头User-Agent
        shuju_1 = request.urlopen(URL, timeout=time_out)   #把URL请求到的数据装入一个变量shuju_1中,设置请求时长timeout,超时就会进行重新尝试
        shuju_2 = shuju_1.readlines()                      #把得到的数据按行读取成行数据列表,装进新变量shuju_2
        guodu = []                                         #设置一个过渡列表
        for a in shuju_2:                                  #遍历shuju_2内的行数据列表
            if yuansu in a.decode('utf-8').strip():        #如果行数据列表中的元素进行utf-8解码后包含指定的信息元素(yuansu)
                guodu.append(a.decode('utf-8').strip())    #就把这个解码后的元素用strip()函数排除前后空白后放入过渡列表
        if len(guodu) <= 1:                                #判断过渡列表中含有的元素个数是否小于等于1
            for i in guodu:                                #如果是,说明只有小于一行符合要求,那么单独抽出这个元素
                shuju_3 = i                                #把这个元素给新变量shuju_3
        else:                                              #如果不是,过渡列表含有多个符合元素
            shuju_3 = guodu                                #则让新变量shuju_3等于这个过渡列表
    except:                                                #如果反复尝试5次之后仍然连接超时
        shuju_3 = ''                                       #则让新变量shuju_3等于空值''
    return shuju_3                                         #对调用函数huoqu返回shuju_3(可能是单个字符串,也可能是列表或者None)

import time,sys                                            #导入sys模块用来显示系统进程,time模块用来显示时间
import re                                                  #导入re模块用来调用split()函数对字符串特定位置进行切割

url = 'http://b2b.huangye88.com/huizhou/'                  #目标网址是某黄页网站某地区的‘首页’,从这个网址获取其他下级页面的URL
url_1 = huoqu(url,'.com',30)                               #调用获取函数,对‘首页’获取其中包括'.com'元素即为网址的行信息,设置时间为30S
url_2 = []                                                 #建立一个空白的列表url_2
for a in url_1:                                            #遍历得到的含有下级url的列表
    if '名录">惠州' in a:                                  #通过查看网页源码可以发现下级网页所在都包含有'名录">惠州',通过这个成分对信息进行一次过滤
        url_2.append(a)                                    #过滤后放入准备好的列表url_2
url_3 = []                                                 #建立一个空白的列表url_3
for b in url_2:                                            #遍历上一次过滤后得到的列表
    C = re.split(r'"',b)                                   #对列表元素进行切割,所有的下级url都用"双引号括起来,用split()在"所在地方切割获得单独的url
    for c in C:                                            #从这种切割后获得的列表中遍历
        if '.com' in c:                                    #如果含有 '.com'即为url,提取出来
            url_3.append(c)                                #放入准备好的列表url_3
Xinxi = []                                                 #建立一个空白的列表Xinxi用来放信息
for d in list(range(1,len(url_3)+1)):                      #建立一个列表用来表示url_3的序数并遍历这个序数列表
    url_4 = url_3[d-1]                                     #把url_3指定位置的元素给变量url_4(这里是循环放入url字符串)
    xinxi = huoqu(url_4, '共收录', 30)                     #目标是找到某城市某行业收录了多少条公司信息,所以依据源码,对'共收录'调用获取函数
    Xinxi.append(xinxi)                                    #把获取的信息xinxi放入专门的列表Xinxi中
                                                           # 这一步用来显示系统循环的进程
    sys.stdout.write('\r[ === [%d/%d] %d%% === ]' % ((d), len(url_3), int((d) /len(url_3) * 100)))
xinxi = {}                                                 #准备一个空字典xinxi,这里的信息个循环内的xinxi不一致不影响
for e in range(0,len(Xinxi)):                              #建立一个列表用来表示Xxinxi的序数并遍历这个序数列表
    E = re.split(r'>|,str(Xinxi[e]))                    #对遍历到的序数位置的元素进行切割,解析源码后知道主要信息被包括在>,
    #print(E)
    xinxi['第'+str(e+1)+'行'] = {}                         #每个行业建立一个行键,显示为第几行数据
    jian = re.split(r'惠州|公司',str(E[2]))                #对切割后的E列表中的第三个元素按照惠州,公司两个进行再切割,得到的新列表第二个元素包含了行业名称
    #print(jian)
    xinxi['第'+str(e+1)+'行']['第'+str(1)+'列']=str(jian[1])#把行业名称放到当行第一列
    xinxi['第'+str(e+1)+'行']['第'+str(2)+'列'] = int(E[6])#把E列表中第7个元素即收录数量放入当行第二列
for a,b in xinxi.items():                                  #遍历一下这个xinxi列表查看下信息是否正确
    print(a,b)
#把表格字典转化成表格样式的一整个字符串 返回字符串
def write_excel(A):                                                                      #创建一个转换字典为特定字符表的函数
    for B,C in A.items():                                                                #遍历表字典内的行:列键值对
        Hang = int(len(A))                                                               #获得行数
        Lie  = int(len(C))                                                               #获得列数
        Lie_Biao = []                                                                    #创建中转列:值对的列表
        Zuizhong = []                                                                    #创建最终所有列值对字符串列表
        for hhh in A.values():                                                           #遍历表中的列字典
            for lll in hhh.values():                                                     #遍历列字典的值
                Lie_Biao.append(str(lll))                                                #把值字符串化添加到值列表
        for hangshu in range(0, Hang + 1):                                               #定义行数为跳转步长
            guodu = Lie_Biao[hangshu * Lie:hangshu * Lie + Lie]                          #定义按每行转化成过渡切片
            jiange_1 = '\t'                                                              #定义一个制表符
            meiyihang = jiange_1.join(guodu)                                             #用制表符来连接切片中的每一列
            Zuizhong.append(meiyihang)                                                   #把由每一列连起来的每一行添加到最终列表
        jiange_2 = '\n'                                                                  #定义一个换行符
        zhenggebiao = jiange_2.join(Zuizhong)                                            #用换行符来连接最终列表内每个行元素
        return zhenggebiao                                                               #返回一个表示整个表的字符串
#把特定的字符串写入特定路径按特定名和格式保存
def save_excel(baocunduixiang,wenjianjialujing,baocunming,geshihouzhui):
    baocunming = str(baocunming)                                                         #指定保存名
    LUJING_NEW = wenjianjialujing + '\\' + baocunming + '.'+ geshihouzhui                #拼装最终路径
    f = open(LUJING_NEW, 'w',encoding='utf-8')                                           # 在目的路径声明一个文件及格式并打开
    f.write(baocunduixiang)                                                              # 把处理好的信息写入这个文件
    f.close()                                                                            # 关闭写入操作

huizhouqiye = write_excel(xinxi)
lujing = input("路径:")
baocun = input("保存文件名:")
save_excel(huizhouqiye,lujing,baocun,'xls')

你可能感兴趣的:(爬虫入门)