利用Scrapy下载世界银行excel文件

本文首发于我的博客:http://gongyanli.com
代码传送门:https://github.com/Gladysgong/wordbank
简书: https://www.jianshu.com/p/b8253ad8054e
CSDN: https://blog.csdn.net/u012052168/article/details/79806493

一、总体思路

    我的目标是下载世界银行中各个指标的excel文件,刚好世界银行给我们提供了excel下载页面的url地址,这样子我们只需要构建url地址进行
请求就好了,还蛮简单的,也不会太大劲。
    首先我需要把所有指标的地址拿到,于是我找到了这个地址**https://data.worldbank.org/indicator?tab=all**,通过这个地址拿到所
有指标的href,再进行拼接,最后把拼接的结果进行请求。
image

二、item模块

class WorldBankItem(scrapy.Item):
    indi_url = scrapy.Field()  # 指标(indicator)的url
    indi_name = scrapy.Field()  # 指标(indicator)的名字

二、爬虫模块

1.解析url
    def parse_urls(self, response):
        item = WorldBankItem()
        selector = scrapy.Selector(response)

        indicators = selector.xpath('//*[@id="main"]/div[2]')
        indi_url = indicators.xpath('section[@class="nav-item"]/ul/li/a/@href').extract()
        # indi = re.findall(r'/indicator/.*/?view=chart', indicators, re.S)
        indi_name = indicators.xpath('section[@class="nav-item"]/ul/li/a/text()').extract()

        for each in indi_url:
            each = each[:-10] + "downloadformat=excel"
            # i.replace("view=chart", "downloadformat=excel") #使用replace进行替换时总是不成功,有待探索!
            item['indi_url'] = each
            print("indi_url", item['indi_url'])
            yield item
            yield scrapy.Request(url="http://api.worldbank.org/v2/en" + each,
                                 callback=self.download_excel)

        for each in indi_name:
            print("indi_name:", each)
            item['indi_name'] = each
            # self.filenames = indi_name
            yield item
2.下载excel文件并写入
    def download_excel(self, response):
        name_temp = response.url.split("/")[-1]
        name = name_temp.split("?")[-2]
        print("storename:", name, '-', response.url)
        filename = r"D:\workspace\scrapy\worldbank\worldbankexcelfiles\%s.xls" % name
        resp = requests.get(response.url)
        output = open(filename, 'wb')
        output.write(resp.content)
        output.close()
        return None

四、数据持久化

1.定义mysql类(属于我单独定义的)
    import pymysql
    class Mysql:
        def __init__(self, host, user, pwd, db):
            self.host = host
            self.user = user
            self.pwd = pwd
            self.db = db
    
        def __GetConnect(self):
            if not self.db:
                raise (NameError, '数据库不存在')
            self.conn = pymysql.connect(host=self.host, user=self.user, password=self.pwd, database=self.db, charset='utf8')
            cur = self.conn.cursor()
            if not cur:
                raise (NameError, '账号或密码错误')
            else:
                return cur
    
        def ExecQuery(self, sql):
            cur = self.__GetConnect()
            cur.execute(sql)
            resList = cur.fetchall()
    
            self.conn.close()
            return resList
    
        def ExecNoQuery(self, sql):
            cur = self.__GetConnect()
            cur.execute(sql)
            self.conn.commit()
            self.conn.close()
2.pipelines
    from worldbank.db.mysql import Mysql
    from worldbank.items import WorldBankItem
    
    
    class WorldbankPipeline(object):
        def process_item(self, item, spider):
            if isinstance(item, WorldBankItem):
                mysql = Mysql(host='localhost', user='root', pwd='421498', db='saas')
                if len(item['indi_name']) == 0:
                    pass
                else:
                    newsql = "insert into worldbank_indi(indi_url,indi_name)values('%s','%s')" % (
                        item['indi_url'], item['indi_name'])
                    print(newsql)
                    mysql.ExecNoQuery(newsql.encode('utf-8'))
            else:
                pass
            return item

五、设置settings

ITEM_PIPELINES = {
    'worldbank.pipelines.WorldbankPipeline': 300,} # 记得开启此处

六、bug

    在爬虫模块parse_urls()中我不光拼接了url地址,我还把指标的url和name放进了item中,因为我这边考虑的,excel文件命名的时候我是
用的url的一部分命名的,像这样子**EN.ATM.GHGO.KT.CE**,这是属于指标名字的简写,的确我们手工下载数据的时候也是以这个命名。但是像我
这种对指标不熟悉的人,完全看不出简写的含义,所以我就想把简写以及指标的全名存储进入数据库,以方便对照,所以我用的yield item这样子来
返回数据。
    但是实际存储的时候,总是报错**KeyError: 'indi_name'**,但是数据也确实存进了数据库,所以我很不理解,这个问题有待于探索,也希
望知道的朋友可以告知。
    本来我也试过用Request中meta来传递item,然后一起返回,但是插入数据库的时候,报错主键的值必须唯一。
    有可能和用的数据库也有关系,用MySQL的数据来存储爬虫数据很不顺手,因为需要自己手工建立数据库和表,或者写代码建立。而MongoDB就很
方便了,告诉数据库名字和表名,自动就帮我们创建了。

七、我是二傻

    原来上面的问题我早就解决了,只是我忘记了,果然好记性不如烂笔头。
parse_url()换成如下:
其实是把两个for改成了一个for,但是这样子就需要把list换成str来进行存储,并且存储的时候我遇到了转义字符的问题,报错如下:
**pymysql.err.ProgrammingError: (1064, 'You have an error in your SQL syntax; check the manual that corresponds to 
your MySQL server version for the right syntax to use near \'Recipe" of Machine Learning","https://i.ytimg.com/vi/
DkgJ_VkU5jM/hqdefault.jpg",\' at line 4')**
改pipelines文件,把字段包裹上pymysql.escape_string(),同时我已经将代码更新,可以自己去看。

    def parse_urls(self, response):
        item = WorldBankItem()
        selector = scrapy.Selector(response)

        indicators = selector.xpath('//*[@id="main"]/div[2]/section[@class="nav-item"]/ul/li')

        for i in indicators:
            temp_url = i.xpath('a/@href').extract()  # 得到的结果为list
            # indi_url = str(temp_url)[:-12] + "downloadformat=excel"
            indi_url = str(temp_url).replace("view=chart", "downloadformat=excel")
            item["indi_url"] = indi_url.replace("'", "").replace("[", "").replace("]", '')
            # print('item["indi_url"]:', item["indi_url"])

            indi_name = i.xpath('a/text()').extract()
            item["indi_name"] = str(indi_name)
            # print('item["indi_name"]:', item["indi_name"])
            yield item

            url = indi_url.replace("'", "").replace("[", "").replace("]", '')
            yield scrapy.Request(url="http://api.worldbank.org/v2/en" + url, callback=self.download_excel)
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,015评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,262评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,727评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,986评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,363评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,610评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,871评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,582评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,297评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,551评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,053评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,385评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,035评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,079评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,841评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,648评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,550评论 2 270

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,569评论 25 707
  • 家长的疑问~ 学围棋对小孩的学习成绩有帮助吗? 小学课业重,不知道需要不需要坚持让孩子学下去! 这是一位家长的网上...
    雪蓉阅读 512评论 0 0
  • 转自:http://www.linuxidc.com/Linux/2011-05/35723.htm 你是否遇到过...
    Devid阅读 1,456评论 6 3
  • 2年前,参加过一个有关财商的培训课,整个课程长达半年,期间安排了一次现金流的游戏,玩过的小伙伴们纷纷表示游戏中能看...
    Shirley千墨阅读 180评论 4 1
  • 读了日本著名推理小说作家东野圭吾的代表作《放学后》感触颇深。1985年至1990年,东野圭吾以校园本格推理...
    1703熊佳欣阅读 134评论 0 0