爬蟲(五)--xpath應用,反爬,動態頁面處理

爬取網站的流程:

  1. 確定網站哪個url是數據的來源
  2. 簡要分析網站結構,查看數據在哪裏
  3. 查看是否有分頁,解決分頁問題
  4. 發送請求,查看response.text裏面是否有我們想要的數據
  5. 如果有數據,提取,保存

注意事項:

  1. 剛開始做爬蟲項目,先不要用類做,只需要關注數據的來源等問題的解決,不要關注封裝結構的處理

一、xpath應用

(一)扇貝單詞項目

在這裏插入圖片描述

import requests,re
from lxml import etree

base_url = 'https://www.shanbay.com/wordlist/110521/232414/?page=%s'
headers = {
    'user-agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36'
}
def get_value(value):
    if value:
        return value[0]
    return ''
result = []
for i in range(1,4):
    response = requests.get(base_url%i,headers=headers)
    html = etree.HTML(response.text)
    # print(etree.tostring(html,pretty_print=True,encoding='utf-8').decode('utf-8'))
    tr_list = html.xpath('//tbody/tr[@class="row"]')
    for tr in tr_list:
        item = {}
        word = get_value(tr.xpath('.//td[@class="span2"]/strong/text()'))
        mean = get_value(tr.xpath('.//td[@class="span10"]/text()'))
        item[word] = mean
        result.append(item)
print(result)

封裝

import requests,json
from lxml import etree

class Shanbei(object):
    def __init__(self,url,headers):
        self.url = url
        self.headers = headers
        self.result = []
        self.word_mean()
        self.save_data()
    def get_value(self,value):
        if value:
            return value[0]
        return ''
    def word_mean(self):
        for i in range(1, 4):
            response = requests.get(self.url % i, headers=headers)
            html = etree.HTML(response.text)
            # print(etree.tostring(html,pretty_print=True,encoding='utf-8').decode('utf-8'))
            tr_list = html.xpath('//tbody/tr[@class="row"]')
            for tr in tr_list:
                item = {}
                word = self.get_value(
                    tr.xpath('.//td[@class="span2"]/strong/text()'))
                mean = self.get_value(tr.xpath('.//td[@class="span10"]/text()'))
                item[word] = mean
                self.result.append(item)
    def save_data(self):
        with open('shanbei_word.json','w',encoding='utf-8') as fp:
            json.dump(self.result,fp)


if __name__ == '__main__':
    base_url = 'https://www.shanbay.com/wordlist/110521/232414/?page=%s'
    headers = {
        'user-agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36'
    }
    Shanbei(base_url,headers)
    with open('shanbei_word.json','r') as fp:
        result = json.load(fp)
    print(result)

(二)網易雲音樂項目

可迭代對象:有__iter__屬性的對象。

迭代器:有__next__屬性的對象。

兩個可以轉換嗎?

iter(可迭代對象)---->返回值爲迭代器

可迭代對象都有哪些?

  • list
  • dict
  • tuple
  • str
  • bytes
  • set
  • 迭代器
  • 生成器
  • 文件流

打印一個文件,同時輸出行號

fp = open('shanbei_word.py','r',encoding='utf-8')
print(fp)
for i,content in enumerate(fp,1):
    print(i,content)

代碼

import requests
from lxml import etree

headers = {
    'user-agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36'
}
def get_xpath(url):
    response = requests.get(url,headers=headers)
    return etree.HTML(response.text)

# 獲取歌手介紹
def get_info(url,item):
    html = get_xpath(url)
    introduce_list = html.xpath('//div[@class="n-artdesc"]/p/text()')
    introduce = ''.join(introduce_list)
    item['introduce'] = introduce
    result.append(item)

# 獲取歌手
def get_single(url):
    html = get_xpath(url)
    single_names = html.xpath('//ul[@id="m-artist-box"]/li/p/a[1]/text()|//ul[@id="m-artist-box"]/li/a[1]/text()')
    single_urls = html.xpath('//ul[@id="m-artist-box"]/li/p/a[1]/@href|//ul[@id="m-artist-box"]/li/a[1]/@href')
    for i,name in enumerate(single_names):
        item = {}
        item['name'] = name
        item['url'] = 'https://music.163.com' + single_urls[i].replace(' ','')
        # 獲取歌手介紹
        url = item['url'].replace('?','/desc?')
        get_info(url,item)

# 獲取姓名首字母分類頁面
def get_type_page(url):
    html = get_xpath(url)
    nametype_url_list = html.xpath('//ul[@id="initial-selector"]/li[position()>1]/a/@href')
    for one in nametype_url_list:
        url = 'https://music.163.com' + one
        # 獲取歌手
        get_single(url)

# 注意錨點
base_url = 'https://music.163.com/discover/artist'
# 獲取歌手地區分類頁面url
def get_type():
    html = get_xpath(base_url)
    localtype_url_list = html.xpath('//ul[@class="nav f-cb"]/li/a[contains(@href,"id")]/@href')
    for one in localtype_url_list:
        url = 'https://music.163.com'+ one
        # 獲取姓名首字母分類頁面
        get_type_page(url)
if __name__ == '__main__':
    result = []
    get_type()
    print(result)

封裝

import requests,json
from lxml import etree

class Music(object):
    def __init__(self,base_url):
        self.base_url = base_url
        self.headers = {
            'user-agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36'
        }
        self.result = []
        self.get_type()
    # 注意錨點
    def get_xpath(self,url):
        response = requests.get(url, headers=self.headers)
        return etree.HTML(response.text)
    # 獲取歌手地區分類頁面url
    def get_type(self):
        html = self.get_xpath(self.base_url)
        localtype_url_list = html.xpath(
            '//ul[@class="nav f-cb"]/li/a[contains(@href,"id")]/@href')
        for one in localtype_url_list:
            url = 'https://music.163.com' + one
            # 獲取姓名首字母分類頁面
            self.get_type_page(url)
    # 獲取姓名首字母分類頁面
    def get_type_page(self,url):
        html = self.get_xpath(url)
        nametype_url_list = html.xpath(
            '//ul[@id="initial-selector"]/li[position()>1]/a/@href')
        for one in nametype_url_list:
            url = 'https://music.163.com' + one
            # 獲取歌手
            self.get_single(url)
    # 獲取歌手
    def get_single(self,url):
        html = self.get_xpath(url)
        single_names = html.xpath(
            '//ul[@id="m-artist-box"]/li/p/a[1]/text()|//ul[@id="m-artist-box"]/li/a[1]/text()')
        single_urls = html.xpath(
            '//ul[@id="m-artist-box"]/li/p/a[1]/@href|//ul[@id="m-artist-box"]/li/a[1]/@href')
        for i, name in enumerate(single_names):
            item = {}
            item['name'] = name
            item['url'] = 'https://music.163.com' + single_urls[i].replace(' ','')
            # 獲取歌手介紹
            url = item['url'].replace('?', '/desc?')
            self.get_info(url, item)
    # 獲取歌手介紹
    def get_info(self,url, item):
        html = self.get_xpath(url)
        introduce_list = html.xpath('//div[@class="n-artdesc"]/p/text()')
        introduce = ''.join(introduce_list)
        item['introduce'] = introduce
        self.result.append(item)

if __name__ == '__main__':
    base_url = 'https://music.163.com/discover/artist'
    m = Music(base_url)
    with open('singer.json','w',encoding='utf-8') as fp:
        json.dump(m.result,fp)

二、反爬措施以及應對措施

反爬策略

1.通過user-agent客戶端表示判斷

解決辦法:將user-agent封裝到請求頭中

2.通過訪問頻率判斷

解決辦法:設置爬取間隔

n = random.randint(5)
time.sleep(n)

3.查封ip

解決辦法:設置代理ip

4.頁面內容無法直接獲取數據,頁面都是js代碼

解決辦法:使用selenium+phantomjs可以獲取頁面數據

selenium+phantomjs

selenium:是web自動測試的工具。

phantomjs:是一個無界面的瀏覽器,所以它可以運行js代碼,幫我們拿到頁面數據。

它們配合使用就可以解決頁面是js代碼的數據獲取問題

下載和安裝
在這裏插入圖片描述
在這裏插入圖片描述
複製到anaconda的script目錄下,然後執行

pip install selenium==2.48.0

在這裏插入圖片描述

爲了使測試工具與瀏覽器交互,需要使用ChromeDriver

查看google版本號
在這裏插入圖片描述
選擇大版本號對應,小版本號最接近的
在這裏插入圖片描述
解壓後同樣放在anaconda的script目錄中

三、動態html頁面的處理方法

(一)常見的頁面技術

1.js

html是頁面的骨架,css是頁面的裝飾,js是頁面的靈魂。

2.jquery

jquery是一個庫,可以使js代碼更加簡化。

3.ajax

是一種技術,web頁面的異步請求。

4.DHTML

DHTML是Dynamic HTML的縮寫,意思是動態的HTML。它並不是一門獨立的語言,實際上任何可以實現頁面動態改變的方法都可以成爲DHTML。

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