前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >「经验」爬虫在工作中的实战应用『实现篇』

「经验」爬虫在工作中的实战应用『实现篇』

作者头像
小火龙说数据
发布2022-06-30 16:59:16
3160
发布2022-06-30 16:59:16
举报
文章被收录于专栏:小火龙说数据小火龙说数据

预计阅读时间:10min

阅读建议:本篇为代码实现,建议收藏,业余时间慢慢研究。

解决痛点:很多同学对于爬虫会有一些疑惑,小火龙希望用简单的语言向你说明爬虫的基本原理,以及如何通过一段简单的代码实现,帮助你尽快上手,文章聚焦于爬虫初学者。

00

序言

上篇文章中,小火龙和大家分享了爬虫的基础原理,回看可戳『理论篇』。本篇,小火龙手把手带你码一个简单的爬虫,附上代码,感兴趣的同学可以自己试一试。

01

爬虫背景

近期,房贷五年期LPR下降,使得购房的贷款成本有所下降,因此想看看北京不同区域,现阶段(2022年5月)vs 疫情前(2019年5月)价格差异。数据来源于「58同城」。

02

爬虫代码

上篇文章『理论篇』中,分享了爬虫的一般流程,这里就不再冗余,直接上代码。

简单介绍一下代码结构,输入文件有四个,输出文件有两个(代码可以写在一个文件中,但介于功能解耦,因此拆分为多个,可重点关注「爬虫核心文件」)。

【输入】

运行主文件(run.py):吊起核心程序的入口文件。

代码语言:javascript
复制
# encoding:utf-8
from configparser import ConfigParser, ExtendedInterpolation
import logging
import sys
import os

FILE_PATH = os.path.dirname(os.path.realpath(__file__))
CONF_PATH = FILE_PATH + '/conf/conf.ini'

# 引入当前文件所在目录下的文件
sys.path.append(FILE_PATH + '/lib')
sys.path.append(FILE_PATH + '/spider')

from InfoSpider import InfoSpider

# 创建log日志函数
def init_logger():
    logger = logging.getLogger()
    logger.setLevel(level = logging.INFO)
    handler = logging.FileHandler("log/log.txt")
    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    handler.setFormatter(formatter)
    logger.addHandler(handler)
    return logger

# 创建conf文件函数
def init_conf(config_path):
    cf = ConfigParser(interpolation=ExtendedInterpolation())
    cf.read(config_path, encoding='utf-8')
    return cf

if __name__ == '__main__':

    logger = init_logger()
    conf = init_conf(CONF_PATH)

    # 爬取58数据
    info_spider = InfoSpider(conf)
    info_spider.getHouseInfo()

爬虫核心文件(InfoSpider.py):实现爬虫的核心功能。

代码语言:javascript
复制
#encoding:utf-8
import logging
import sys
import os
import urllib
import urllib.request, urllib.parse
import re
import time
import random
from GeneralObj import GeneralObj

FILE_PATH = os.path.dirname(os.path.realpath(__file__))
FILE_PATH_MAIN = os.path.join(os.path.dirname(os.path.realpath(__file__)), "../")

#引入当前文件所在目录下的文件
sys.path.append(FILE_PATH_MAIN + '/lib')

logger = logging.getLogger(__name__)
obj = GeneralObj()

class InfoSpider(object):

    def __init__(self, conf):
        self.conf = conf

        #随机获取ua、ip
        ua_conf = self.conf.get('spider_58', 'ua')
        self.ua_list = ua_conf.strip().split('\\001')
        ip_conf = self.conf.get('spider_58', 'ip')
        self.ip_list = ip_conf.strip().split(',')

    def getHouseInfo(self):
        begin_time = time.time()

        #获取细分区域网址
        self.getHouseInfo_area()

        #获取细分区域商圈网址
        self.getHouseInfo_page()

        #获取细分区域商圈数据
        self.getHouseInfo_detail()

        end_time = time.time()
        cost_time = (end_time - begin_time)//60
        logger.info('cost time(min) : %i' % cost_time)
        print('cost time(min) : %i' % cost_time)

    def getHouseInfo_area(self):
        logger.info('begin1 getHouseInfo_area url')
        print('begin1 getHouseInfo_area url')

        main_url = 'https://www.58.com/fangjiawang/shi-2022-100/'
        headers = {"User-Agent": random.sample(self.ua_list, 1)[0]}
        req = urllib.request.Request(main_url, headers=headers)
        data = urllib.request.urlopen(req).read()
        data = data.decode('utf-8')

        data_filter = re.findall('<ul class="sel-sec" data-v-4571decc>(.*?)</ul>', data)
        data_list = re.findall('<a href="(.*?)"', data_filter[0])[1:]
        obj.recordsToFile(data_list, './data/getHouseInfo_area.txt', type=1, delimiter="\t", mode="w")

        logger.info('finish1 getHouseInfo_area url')
        print('finish1 getHouseInfo_area url')

    def getHouseInfo_page(self):
        logger.info('begin2 getHouseInfo_page url')
        print('begin2 getHouseInfo_page url')

        area_url_list = obj.fileToRecords('./data/getHouseInfo_area.txt', 1)
        area_url_num = len(area_url_list)
        area_url_counts = 1

        for line in area_url_list:
            headers = {"User-Agent": random.sample(self.ua_list, 1)[0]}
            req = urllib.request.Request(line, headers=headers)
            data = urllib.request.urlopen(req).read()
            data = data.decode('utf-8')

            data_filter = re.findall('<ul class="sel-thi" data-v-4571decc>(.*?)</ul>', data)
            data_list = re.findall('<a href="(.*?)"', data_filter[0])[1:]
            obj.recordsToFile(data_list, './data/getHouseInfo_page.txt', type=1, delimiter="\t", mode="a+")

            logger.info('getHouseInfo_page url progress: %i/%i' % (area_url_counts, area_url_num))
            print('getHouseInfo_page url progress: %i/%i' % (area_url_counts, area_url_num))

            time.sleep(2)
            area_url_counts += 1

    def getHouseInfo_detail(self):
        logger.info('begin3 getHouseInfo_detail url')
        print('begin3 getHouseInfo_detail url')

        detail_url_list = obj.fileToRecords('./data/getHouseInfo_page.txt', 1)
        detail_url_num = len(detail_url_list)
        detail_url_counts = 1

        for line in detail_url_list:

            try:
                address2022 = line
                address2019 = line.replace('shi-2022-100', 'shi-2019-100')
                headers = {"User-Agent": random.sample(self.ua_list, 1)[0]}
                req2022 = urllib.request.Request(address2022, headers=headers)
                req2019 = urllib.request.Request(address2019, headers=headers)
                data2022 = urllib.request.urlopen(req2022).read()
                data2019 = urllib.request.urlopen(req2019).read()
                data2022 = data2022.decode('utf-8')
                data2019 = data2019.decode('utf-8')
                area_list = []

                # 获取2022
                data_bigarea = re.findall('<div class="m-t mt20" data-v-2a40ba50>2022(.*?)各板块二手房均价</div>', data2022)
                area_list.append(data_bigarea[0])
                data_area = re.findall('2022年(.*?)房价走势图', data2022)
                area_list.append(data_area[0])
                data_price_2022 = re.findall('2022年5月房价</b><span data-v-2a40ba50>(.*?)元/㎡', data2022)
                area_list.append(data_price_2022[0])
                # 获取2019
                data_price_2019 = re.findall('2019年5月房价</b><span data-v-2a40ba50>(.*?)元/㎡', data2019)
                area_list.append(data_price_2019[0])
                obj.recordsToFile(area_list, './data/getHouseInfo_detail.txt', type=4, delimiter="\t", mode="a+")

                logger.info('getHouseInfo_detail progress: %i/%i content:%s' % (detail_url_counts, detail_url_num, area_list))
                print('getHouseInfo_detail progress: %i/%i content:%s' % (detail_url_counts, detail_url_num, area_list))

                time.sleep(2)
                detail_url_counts += 1
            except:
                logger.info('getHouseInfo_detail progress: %i/%i NO CONTENT:%s' % (detail_url_counts, detail_url_num, line))
                print('getHouseInfo_detail progress: %i/%i NO CONTENT:%s' % (detail_url_counts, detail_url_num, line))

                time.sleep(2)
                detail_url_counts += 1
                continue

配置文件(conf.ini):放置经常需更改的变量(此处筛选部分)。

代码语言:javascript
复制
[spider_58]
ua = Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.1; WOW64; Trident/4.0)\001Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)\001Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1
ip = 125.112.76.113,110.85.124.116

自定义函数文件(GeneralObj.py):放置用户自定义函数。

代码语言:javascript
复制
#encoding:utf-8
import logging
import sys, os
import time
import random

FILE_PATH = os.path.dirname(os.path.realpath(__file__))

#引入当前文件所在目录下的文件
sys.path.append(FILE_PATH + '../data')

class GeneralObj(object):

    def __init__(self):
        self.logger = logging.getLogger(__name__)

    #传入list,存储到本地文件
    def recordsToFile(self, records, file_name, type=1, delimiter="\t", mode="w"):
        f = open(file_name, mode)
        if type==1:
            for line in records:
                f.write(line + "\n")
            f.close()
        if type==2:
            for line in records:
                f.write(delimiter.join(line) + "\n")
            f.close()
        if type==3:
            f.write(records)
            f.close()
        if type==4:
            f.write(delimiter.join(records) + "\n")
            f.close()

    #读取本地文件,存入list
    def fileToRecords(self, file_name, type=1, delimiter="\t", mode="r"):
        lists = []
        f = open(file_name, mode)
        if type==1:
            for line in f.readlines():
                lists.append(line.strip())
            f.close()
            return lists
        if type==2:
            for line in f.readlines():
                lists.append(line.strip().split(delimiter))
            f.close()
            return lists

【输出】

日志文件(log.txt):记录运行日志,方便在出现问题时进行排查。

爬取结果文件(data.txt):放置爬取结果。

03

数据分析

以下为数据爬取后,北京城六区整体数据及各区域价格涨幅TOP5商圈。

以上就是本期的内容分享。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2022-06-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 小火龙说数据 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档