1. 程式人生 > >Python網絡爬蟲之三種數據解析方式

Python網絡爬蟲之三種數據解析方式

循環 oob bs4 none @class clas sel 執行 替換

一.正則解析

  單字符:
        . : 除換行以外所有字符
        [] :[aoe] [a-w] 匹配集合中任意一個字符
        \d :數字  [0-9]
        \D : 非數字
        \w :數字、字母、下劃線、中文
        \W : 非\w
        \s :所有的空白字符包,括空格、制表符、換頁符等等。等價於 [ \f\n\r\t\v]。
        \S : 非空白
    數量修飾:
        * : 任意多次  >=0
        + : 至少1次   >=1
        ? : 可有可無  0次或者1次
        {m} :固定m次 hello{
3,} {m,} :至少m次 {m,n} :m-n次 邊界: $ : 以某某結尾 ^ : 以某某開頭 分組: (ab) 貪婪模式 .* 非貪婪(惰性)模式 .*? re.I : 忽略大小寫 re.M :多行匹配 re.S :單行匹配 re.sub(正則表達式, 替換內容, 字符串)

  - 基礎鞏固:

import re
#提取出python
key="javapythonc++php"
pl=python #正則表達式
re.findall(pl,key) #
findall返回的是一個列表
#提取出hello world
key="<html><h1>hello world<h1></html>"
pl=<h1>(.*)<h1>
re.findall(pl,key)[0]
#提取170
string = 我喜歡身高為170的女孩
pl=\d+
re.findall(pl,string)[0]
#提取出http://和https://
key=http://www.baidu.com and https://boob.com
pl=https*://
re.findall(pl,key)
#提取出hello
key=lalala<hTml>hello</HtMl>hahah #輸出<hTml>hello</HtMl>
pl=<[hH][tT][mM][lL]>(.*)</[hH][tT][mM][lL]>
re.findall(pl,key)[0]
#提取出hit :貪婪模式:盡可能多的匹配數據
key=[email protected]#想要匹配到hit.
pl=h.*\.
re.findall(pl,key)
key=[email protected]#想要匹配到hit.
pl=h.*?\.
re.findall(pl,key)
#{a,b}表示其前一個字符或者表達式可以重復的範圍是 a<=次數<=b
key=saas and sas and saaas#匹配sas和saas
pl=sa{1,2}s
re.findall(pl,key)
#匹配出i開頭的行
string = ‘‘‘fall in love with you
i love you very much
i love she
i love her‘‘‘

pl=^i.*
#re.M或者re.S或者re.I只可以作為compile函數的第二個參數
pa=re.compile(pl,re.M)
pa.findall(string)
#匹配全部行
string1 = """<div>靜夜思
窗前明月光
疑是地上霜
舉頭望明月
低頭思故鄉
</div>"""

pl=<div>(.*)</div>
pa=re.compile(pl,re.S)
pa.findall(string1)

  -綜合練習:

    需求:爬取糗事百科指定頁面的糗圖,並將其保存到指定文件夾中

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import requests
import re
import os
if __name__ == "__main__":
     url = https://www.qiushibaike.com/pic/%s/
     headers={
         User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36,
     }
     #指定起始也結束頁碼
     page_start = int(input(enter start page:))
     page_end = int(input(enter end page:))

     #創建文件夾
     if not os.path.exists(images):
         os.mkdir(images)
     #循環解析且下載指定頁碼中的圖片數據
     for page in range(page_start,page_end+1):
         print(正在下載第%d頁圖片%page)
         new_url = format(url % page)
         response = requests.get(url=new_url,headers=headers)

         #解析response中的圖片鏈接
         e = <div class="thumb">.*?<img src="(.*?)".*?>.*?</div>
         pa = re.compile(e,re.S)
         image_urls = pa.findall(response.text)
          #循環下載該頁碼下所有的圖片數據
         for image_url in image_urls:
             image_url = https: + image_url
             image_name = image_url.split(/)[-1]
             image_path = images/+image_name

             image_data = requests.get(url=image_url,headers=headers).content
             with open(image_path,wb) as fp:
                 fp.write(image_data)

二.bs4解析

  - 環境安裝:

- 需要將pip源設置為國內源,阿裏源、豆瓣源、網易源等
   - windows
    (1)打開文件資源管理器(文件夾地址欄中)
    (2)地址欄上面輸入 %appdata%3)在這裏面新建一個文件夾  pip
    (4)在pip文件夾裏面新建一個文件叫做  pip.ini ,內容寫如下即可
        [global]
        timeout = 6000
        index-url = https://mirrors.aliyun.com/pypi/simple/
        trusted-host = mirrors.aliyun.com
   - linux
    (1)cd ~2)mkdir ~/.pip
    (3)vi ~/.pip/pip.conf
    (4)編輯內容,和windows一模一樣
  - 需要安裝:pip install bs4
    bs4在使用時候需要一個第三方庫,把這個庫也安裝一下
    pip install lxml

  - 簡單使用規則:

        - from bs4 import BeautifulSoup
        - 使用方式:可以將一個html文檔,轉化為BeautifulSoup對象,然後通過對象的方法或者屬性去查找指定的內容
          (1)轉化本地文件:
              - soup = BeautifulSoup(open(本地文件), lxml)
          (2)轉化網絡文件:
              - soup = BeautifulSoup(字符串類型或者字節類型, lxml)
          (3)打印soup對象顯示內容為html文件中的內容
    (1)根據標簽名查找
        - soup.a   只能找到第一個符合要求的標簽
    (2)獲取屬性
        - soup.a.attrs  獲取a所有的屬性和屬性值,返回一個字典
        - soup.a.attrs[href]   獲取href屬性
        - soup.a[href]   也可簡寫為這種形式
    (3)獲取內容
        - soup.a.string
        - soup.a.text
        - soup.a.get_text()
       【註意】如果標簽還有標簽,那麽string獲取到的結果為None,而其它兩個,可以獲取文本內容
    (4)find:找到第一個符合要求的標簽
        - soup.find(a)  找到第一個符合要求的
        - soup.find(a, title="xxx")
        - soup.find(a, alt="xxx")
        - soup.find(a, class_="xxx")
        - soup.find(a, id="xxx")
    (5)find_all:找到所有符合要求的標簽
        - soup.find_all(a)
        - soup.find_all([a,b]) 找到所有的a和b標簽
        - soup.find_all(a, limit=2)  限制前兩個
    (6)select:soup.select(#feng)
        - 根據選擇器選擇指定的內容
        - 常見的選擇器:標簽選擇器(a)、類選擇器(.)、id選擇器(#)、層級選擇器
            - 層級選擇器:
                div .dudu #lala .meme .xixi  下面好多級
                div > p > a > .lala          只能是下面一級
        【註意】select選擇器返回永遠是列表,需要通過下標提取指定的對象

  - 綜合練習:

    需求:使用bs4實現將詩詞名句網站中三國演義小說的每一章的內容爬去到本地磁盤進行存儲 http://www.shicimingju.com/book/sanguoyanyi.html

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import requests
from bs4 import BeautifulSoup

headers={
         User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36,
     }
def parse_content(url):
    #獲取標題正文頁數據
    page_text = requests.get(url,headers=headers).text
    soup = BeautifulSoup(page_text,lxml)
    #解析獲得標簽
    ele = soup.find(div,class_=chapter_content)
    content = ele.text #獲取標簽中的數據值
    return content

if __name__ == "__main__":
     url = http://www.shicimingju.com/book/sanguoyanyi.html
     reponse = requests.get(url=url,headers=headers)
     page_text = reponse.text

     #創建soup對象
     soup = BeautifulSoup(page_text,lxml)
     #解析數據
     a_eles = soup.select(.book-mulu > ul > li > a)
     print(a_eles)
     cap = 1
     for ele in a_eles:
         print(開始下載第%d章節%cap)
         cap+=1
         title = ele.string
         content_url = http://www.shicimingju.com+ele[href]
         content = parse_content(content_url)

         with open(./sanguo.txt,w) as fp:
             fp.write(title+":"+content+\n\n\n\n\n)
             print(結束下載第%d章節%cap)

三.xpath解析

from lxml import etree
    兩種方式使用:將html文檔變成一個對象,然後調用對象的方法去查找指定的節點
    (1)本地文件
        tree = etree.parse(文件名)
    (2)網絡文件
        tree = etree.HTML(網頁字符串)

    ret = tree.xpath(路徑表達式)
    【註】ret是一個列表

  參考文獻:http://www.w3school.com.cn/xpath/xpath_intro.asp

  - 安裝xpath插件:可以在插件中直接執行xpath表達式

    1.將xpath插件拖動到谷歌瀏覽器拓展程序(更多工具)中,安裝成功

    2.啟動和關閉插件 ctrl + shift + x

  - 常用表達式:

/bookstore/book           選取根節點bookstore下面所有直接子節點book
    //book                    選取所有book
    /bookstore//book          查找bookstore下面所有的book
    /bookstore/book[1]        bookstore裏面的第一個book
    /bookstore/book[last()]   bookstore裏面的最後一個book
    /bookstore/book[position()<3]  前兩個book
    //title[@lang]            所有的帶有lang屬性的title節點
    //title[@lang=eng]      所有的lang屬性值為eng的title節點
    屬性定位
            //li[@id="hua"]
            //div[@class="song"]
    層級定位&索引
            //div[@id="head"]/div/div[2]/a[@class="toindex"]
            【註】索引從1開始
            //div[@id="head"]//a[@class="toindex"]
            【註】雙斜杠代表下面所有的a節點,不管位置
     邏輯運算
            //input[@class="s_ipt" and @name="wd"]
     模糊匹配 :
          contains
                //input[contains(@class, "s_i")]
                所有的input,有class屬性,並且屬性中帶有s_i的節點
                //input[contains(text(), "")]
            starts-with
                //input[starts-with(@class, "s")]
                所有的input,有class屬性,並且屬性以s開頭
      取文本
            //div[@id="u1"]/a[5]/text()  獲取節點內容
            //div[@id="u1"]//text()      獲取節點裏面不帶標簽的所有內容
      取屬性
            //div[@id="u1"]/a[5]/@href    

  

  - 代碼中使用xpath:

    1.導包:from lxml import etree

    2.將html文檔或者xml文檔轉換成一個etree對象,然後調用對象中的方法查找指定的節點

      2.1 本地文件:tree = etree.parse(文件名)

      2.2 網絡數據:tree = etree.HTML(網頁內容字符串)

  - 綜合練習:

    需求:獲取好段子中段子的內容和作者 http://www.haoduanzi.com

from lxml import etree
import requests

url=http://www.haoduanzi.com/category-10_2.html
headers = {
        User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36,
    }
url_content=requests.get(url,headers=headers).text
#使用xpath對url_conten進行解析
#使用xpath解析從網絡上獲取的數據
tree=etree.HTML(url_content)
#解析獲取當頁所有段子的標題
title_list=tree.xpath(//div[@class="log cate10 auth1"]/h3/a/text())

ele_div_list=tree.xpath(//div[@class="log cate10 auth1"])

text_list=[] #最終會存儲12個段子的文本內容
for ele in ele_div_list:
    #段子的文本內容(是存放在list列表中)
    text_list=ele.xpath(./div[@class="cont"]//text())
    #list列表中的文本內容全部提取到一個字符串中
    text_str=str(text_list)
    #字符串形式的文本內容防止到all_text列表中
    text_list.append(text_str)
print(title_list)
print(text_list)

Python網絡爬蟲之三種數據解析方式