Python手記-8:python一次性爬取多頁數據並存入CSV文件

目錄

1. 一次性爬取多頁豆瓣繪本數據

2. 爬取多頁豆瓣繪本數據存入CSV文件

1. 一次性爬取多頁豆瓣繪本數據

Python手記-7中實現了單頁爬取數據,本節來試試多頁數據爬取,案例背景爲豆瓣圖書網頁實現繪本的多頁數據爬取,先看看網址信息:

複製出來:

第一頁:https://book.douban.com/tag/%E7%BB%98%E6%9C%AC?start=0&type=T

第二頁:https://book.douban.com/tag/%E7%BB%98%E6%9C%AC?start=20&type=T

第三頁:https://book.douban.com/tag/%E7%BB%98%E6%9C%AC?start=40&type=T

……

在原網址裏的中文字符“繪本”複製出來變成了“%E7%BB%98%E6%9C%AC”,這個是URL編碼問題,用哪個都不影響爬取;

觀察推斷url變化規律,變化的只是start參數值,且start值是首項爲0,公差爲20的等差遞增數列:

第i頁:https://book.douban.com/tag/%E7%BB%98%E6%9C%AC?start=(i-1)* 20&type=T

下面就粗略的試試看:

# -*- coding: utf-8 -*- 
# @Time : 2020/4/27 14:14
# @Author : ChengYu
# @File : requests_getbooks.py

import requests
import re

# 加上headers用來告訴網站這是通過一個瀏覽器進行的訪問
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
                         'Chrome/81.0.4044.122 Safari/537.36'}
# page_index起始值爲0,爬取20頁
for page_index in range(20):
    url = 'https://book.douban.com/tag/%E7%BB%98%E6%9C%AC?start=' + str(page_index * 20) + '&type=T'
    # url = 'https://book.douban.com/tag/繪本?start=' + str(page_index * 20) + '&type=T'

    # 獲取網頁源碼
    res = requests.get(url, headers=headers).text
    # 獲取繪本鏈接、作者信息、書名、評價數、簡介
    p_href = '<h2 class="">.*?<a href="(.*?)"'
    href = re.findall(p_href, res, re.S)
    p_info = '<div class="pub">(.*?)</div>'
    info = re.findall(p_info, res, re.S)
    # p_title = '<h2 class="">.*?>(.*?)</a>'
    p_title = '<h2 class="">.*?title="(.*?)"'
    title = re.findall(p_title, res, re.S)
    p_appraise = '<span class="pl">(.*?)</span>'
    appraise = re.findall(p_appraise, res, re.S)
    # p_detail = '<div class="info">.*?<p>(.*?)</p>'
    # detail = re.findall(p_detail, res, re.S)

    for i in range(len(title)):
        title[i] = title[i].strip()
        info[i] = info[i].strip()
        appraise[i] = appraise[i].strip()
        href[i] = href[i].strip()
        # detail[i] = detail[i].strip()
        # 出去換行符
        # detail[i] = re.sub('\n', '', detail[i])
        print(str(i + 1) + '.' + title[i] + ' ' + href[i] + '\n' + info[i] + '\n' + appraise[i])
        
    print('第' + str(page_index + 1) + '頁爬取成功')

“run”一下看看結果,書名、鏈接、作者/出版等信息、評論數了然在列:

2. 爬取多頁豆瓣繪本數據存入CSV文件

CSV模塊是實現以CSV格式讀取和寫入表格數據的類,CSV模塊主要功能(官文:https://docs.python.org/3.8/library/csv.html):

(1)csv.reader(csvfiledialect='excel'**fmtparams)/csv.writer(csvfiledialect='excel'**fmtparams):csvfile可以是支持迭代器協議並在每次__next__()調用其方法時都返回字符串的任何對象- 文件對象和列表對象均適用,簡言之Excel或者CSV文件都可以;其中的Dialects and Formatting參數:

  • Dialect.delimiter:分隔字段的字符,默認爲',';
  • Dialect.doublequote:雙引號,當單引號已經被定義,並且quoting參數不是QUOTE_NONE的時候,使用雙引號表示引號內的元素作爲一個元素使用;
  • Dialect.escapechar:當quoting 爲QUOTE_NONE時,指定一個字符使的不受分隔符限值,默認爲None,將禁用轉義;
  • Dialect.lineterminator:行分隔符,默認爲'\r\n';
  • Dialect.quotechar:引用符,用於引用包含特殊字符(例如定界符或quotechar)或包含換行符的字段,默認爲'"'。
  • Dialect.quoting:控制csv中的引號常量,可選QUOTE_*常量,默認爲QUOTE_MINIMAL;
  • Dialect.skipinitialspace:如果爲True,則分隔符後的空白將被忽略,默認值爲False;
  • Dialect.strict:如果爲True,則Error在CSV輸入錯誤時引發異常,默認值爲False。

(2)csv.DictReader(f,fieldnames=Nonerestkey=Nonerestval=Nonedialect='excel'*args**kwds)/csv.DictWriter(f, fieldnames, restval='', extrasaction='raise', dialect='excel', *args, **kwds):

  • fieldnames:字段名列表,默認是第一行的數據;
  • restkey:當實際的字段數大於字段名數量時,多出來的字段名稱就是這個restkey指定(默認爲None);
  • restval:如果非空白行的字段少於字段名,則缺少的值將填充爲restval的值(默認爲None);
  • extrasaction:當數據中有額外的字段時所採取的操作,默認爲’raise’,即拋異常,有時候這種情況比較煩,所以還可以設置成’ignore’直接忽略。

(3)csvreader.fieldnames:字段名稱,默認是第一行的數據。

(4)csvwriter.writerow(row)/csvwriter.writerows(rows):單行寫入/多行寫入。

(5)DictWriter.writeheader():寫入字段名稱,也就是csv頭部信息。

寫入用法示例(偷懶了,來源官文):

import csv

with open('names.csv', 'w', newline='') as csvfile:
    fieldnames = ['first_name', 'last_name']
    writer = csv.DictWriter(csvfile, fieldnames=fieldnames)

    writer.writeheader()
    writer.writerow({'first_name': 'Baked', 'last_name': 'Beans'})
    writer.writerow({'first_name': 'Lovely', 'last_name': 'Spam'})
    writer.writerow({'first_name': 'Wonderful', 'last_name': 'Spam'})

讀取用法示例(偷懶了,來源官文):

import csv
with open('some.csv', newline='', encoding='utf-8') as f:
    reader = csv.reader(f)
    for row in reader:
        print(row)

學以致用,接下來在前面的案例基礎上改動一下,繼續爬取豆瓣繪本前10頁的書本數據,並稍微美化一下輸出,以CSV文件格式保存數據。

# -*- coding: utf-8 -*- 
# @Time : 2020/4/27 14:14 
# @Author : ChengYu 
# @File : requests_getbooks.py

import requests
import re
import csv

# 加上headers用來告訴網站這是通過一個瀏覽器進行的訪問
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) '
                         'Chrome/81.0.4044.122 Safari/537.36'}
# 初始化csv文件
with open('books.csv', 'w', newline='', encoding='utf-8') as csvfile:
    writer = csv.writer(csvfile)
    writer.writerow(['序號', '書名', '評分', '評論人數', '作者/出版社/出版日期/價格', '鏈接'])
    # bookinfo = []
    count = 1
    # page_index起始值爲0,爬取10頁
    for page_index in range(10):
        url = 'https://book.douban.com/tag/%E7%BB%98%E6%9C%AC?start=' + str(page_index * 20) + '&type=T'
        # url = 'https://book.douban.com/tag/繪本?start=' + str(page_index * 20) + '&type=T'

        # 獲取網頁源碼
        res = requests.get(url, headers=headers).text
        # 獲取繪本鏈接、作者信息、書名、評價數、簡介
        p_href = '<h2 class="">.*?<a href="(.*?)"'
        href = re.findall(p_href, res, re.S)
        p_info = '<div class="pub">(.*?)</div>'
        info = re.findall(p_info, res, re.S)
        # p_title = '<h2 class="">.*?>(.*?)</a>'
        p_title = '<h2 class="">.*?title="(.*?)"'
        title = re.findall(p_title, res, re.S)
        p_grade = '<span class="rating_nums">(.*?)</span>'
        grade = re.findall(p_grade, res, re.S)
        p_appraise = '<span class="pl">(.*?)</span>'
        appraise = re.findall(p_appraise, res, re.S)

        # p_detail = '<div class="info">.*?<p>(.*?)</p>'
        # detail = re.findall(p_detail, res, re.S)

        for j in range(len(title)):
            title[j] = title[j].strip()
            info[j] = info[j].strip()
            appraise[j] = appraise[j].strip().replace('(', '').replace('人評價)', '')
            grade[j] = grade[j].strip()
            href[j] = href[j].strip()
            writer.writerow([count, title[j], grade[j], appraise[j], info[j], href[j]])
            # print(title[i], info[i], href[i], appraise[i])
            # bookinfo.append([title[i], info[i], href[i], appraise[i]])
            # print('第' + str(i + 1) + '頁爬取成功')
            count += 1

    # 注意csvfile.close()縮進問題,這應該是與for同級別,否則可能造成:ValueError: I/O operation on closed file.
    csvfile.close()

“run”之後會在當前project目錄生成books.csv,內容顯示如下,序號不再是1-20的循環,而是從1一直遞增到爬取結束,評論人數從(558486人評價)變爲558486,增加評分列爬取,當然也可以增加其他的爬取內容,無外乎就是正則和re庫方法的使用。

叮!淺嘗輒止,這個主題暫時下課! 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章