爬蟲系列(十) 用requests和xpath爬取豆瓣電影

這篇文章咱們將使用 requests 和 xpath 爬取豆瓣電影 Top250,下面先貼上最終的效果圖:html

一、網頁分析

(1)分析 URL 規律

咱們首先使用 Chrome 瀏覽器打開 豆瓣電影 Top250,很容易能夠判斷出網站是一個靜態網頁python

而後咱們分析網站的 URL 規律,以便於經過構造 URL 獲取網站中全部網頁的內容json

首頁:https://movie.douban.com/top250瀏覽器

第二頁:https://movie.douban.com/top250?start=25&filter=網絡

第三頁:https://movie.douban.com/top250?start=50&filter=dom

...工具

不難發現,URL 能夠泛化爲 https://movie.douban.com/top250?start={page}&filter=,其中,page 表明頁數網站

最後咱們還須要驗證一下首頁的 URL 是否也知足規律,通過驗證,很容易能夠發現首頁的 URL 也知足上面的規律編碼

核心代碼以下:url

import requests
# 獲取網頁源代碼
def get_page(url):
    # 構造請求頭部
    headers = {
        'USER-AGENT':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36'
    }
    # 發送請求,得到響應
    response = requests.get(url=url,headers=headers)
    # 得到網頁源代碼
    html = response.text
    # 返回網頁源代碼
    return html

(2)分析內容規律

接下來咱們開始分析每個網頁的內容,並從中提取出須要的數據

使用快捷鍵 Ctrl+Shift+I 打開開發者工具,選中 Elements 選項欄分析網頁的源代碼

須要提取的數據包括(能夠使用 xpath 進行匹配):

  • 詳細連接:html.xpath('//div[@class="hd"]/a/@href')
  • 電影名稱:html.xpath('//div[@class="hd"]/a/span[1]/text()')
  • 導演/主演、上映年份/國家/分類:html.xpath('//div[@class="bd"]/p[1]//text()')
  • 豆瓣評分:html.xpath('//div[@class="bd"]/div/span[2]/text()')
  • 評價人數:html.xpath('//div[@class="bd"]/div/span[4]/text()')

核心代碼以下:

from lxml import etree
# 解析網頁源代碼
def parse_page(html):
    # 構造 _Element 對象
    html_elem = etree.HTML(html)
    # 詳細連接
    links = html_elem.xpath('//div[@class="hd"]/a/@href')
    # 電影名稱
    titles = html_elem.xpath('//div[@class="hd"]/a/span[1]/text()')
    # 電影信息(導演/主演、上映年份/國家/分類)
    infos = html_elem.xpath('//div[@class="bd"]/p[1]//text()')
    roles = [j for i,j in enumerate(infos) if i % 2 == 0]
    descritions = [j for i,j in enumerate(infos) if i % 2 != 0]
    # 豆瓣評分
    stars = html_elem.xpath('//div[@class="bd"]/div/span[2]/text()')
    # 評論人數
    comments = html_elem.xpath('//div[@class="bd"]/div/span[4]/text()')
    # 得到結果
    data = zip(links,titles,roles,descritions,stars,comments)
    # 返回結果
    return data

(3)保存數據

下面將數據分別保存爲 txt 文件、json 文件和 csv 文件

import json
import csv
# 打開文件
def openfile(fm):
    fd = None
    if fm == 'txt':
        fd = open('douban.txt','w',encoding='utf-8')
    elif fm == 'json':
        fd = open('douban.json','w',encoding='utf-8')
    elif fm == 'csv':
        fd = open('douban.csv','w',encoding='utf-8',newline='')
    return fd

# 將數據保存到文件
def save2file(fm,fd,data):
    if fm == 'txt':
        for item in data:
            fd.write('----------------------------------------\n')
            fd.write('link:' + str(item[0]) + '\n')
            fd.write('title:' + str(item[1]) + '\n')
            fd.write('role:' + str(item[2]) + '\n')
            fd.write('descrition:' + str(item[3]) + '\n')
            fd.write('star:' + str(item[4]) + '\n')
            fd.write('comment:' + str(item[5]) + '\n')
    if fm == 'json':
        temp = ('link','title','role','descrition','star','comment')
        for item in data:
            json.dump(dict(zip(temp,item)),fd,ensure_ascii=False)
    if fm == 'csv':
        writer = csv.writer(fd)
        for item in data:
            writer.writerow(item)

二、編碼實現

下面是完整代碼,也是幾十行能夠寫完

import requests
from lxml import etree
import json
import csv
import time
import random

# 獲取網頁源代碼
def get_page(url):
    headers = {
        'USER-AGENT':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36'
    }
    response = requests.get(url=url,headers=headers)
    html = response.text
    return html

# 解析網頁源代碼
def parse_page(html):
    html_elem = etree.HTML(html)
    links = html_elem.xpath('//div[@class="hd"]/a/@href')
    titles = html_elem.xpath('//div[@class="hd"]/a/span[1]/text()')
    infos = html_elem.xpath('//div[@class="bd"]/p[1]//text()')
    roles = [j.strip() for i,j in enumerate(infos) if i % 2 == 0]
    descritions = [j.strip() for i,j in enumerate(infos) if i % 2 != 0]
    stars = html_elem.xpath('//div[@class="bd"]/div/span[2]/text()')
    comments = html_elem.xpath('//div[@class="bd"]/div/span[4]/text()')
    data = zip(links,titles,roles,descritions,stars,comments)
    return data

# 打開文件
def openfile(fm):
    fd = None
    if fm == 'txt':
        fd = open('douban.txt','w',encoding='utf-8')
    elif fm == 'json':
        fd = open('douban.json','w',encoding='utf-8')
    elif fm == 'csv':
        fd = open('douban.csv','w',encoding='utf-8',newline='')
    return fd

# 將數據保存到文件
def save2file(fm,fd,data):
    if fm == 'txt':
        for item in data:
            fd.write('----------------------------------------\n')
            fd.write('link:' + str(item[0]) + '\n')
            fd.write('title:' + str(item[1]) + '\n')
            fd.write('role:' + str(item[2]) + '\n')
            fd.write('descrition:' + str(item[3]) + '\n')
            fd.write('star:' + str(item[4]) + '\n')
            fd.write('comment:' + str(item[5]) + '\n')
    if fm == 'json':
        temp = ('link','title','role','descrition','star','comment')
        for item in data:
            json.dump(dict(zip(temp,item)),fd,ensure_ascii=False)
    if fm == 'csv':
        writer = csv.writer(fd)
        for item in data:
            writer.writerow(item)

# 開始爬取網頁
def crawl():
    url = 'https://movie.douban.com/top250?start={page}&filter='
    fm = input('請輸入文件保存格式(txt、json、csv):')
    while fm!='txt' and fm!='json' and fm!='csv':
        fm = input('輸入錯誤,請從新輸入文件保存格式(txt、json、csv):')
    fd = openfile(fm)
    print('開始爬取')
    for page in range(0,250,25):
        print('正在爬取第 ' + str(page+1) + ' 頁至第 ' + str(page+25) + ' 頁......')
        html = get_page(url.format(page=str(page)))
        data = parse_page(html)
        save2file(fm,fd,data)
        time.sleep(random.random())
    fd.close()
    print('結束爬取')

if __name__ == '__main__':
    crawl()

【爬蟲系列相關文章】

相關文章
相關標籤/搜索
本站公眾號
   歡迎關注本站公眾號,獲取更多信息