記一次基於Cloudflare服務的爬蟲

Asche發表於2019-07-06

前言

前幾天有個朋友託我幫忙爬一個網站,第一次開啟那個網站時,我去,它竟然就要驗證碼,不過當時是想加幾個header應該就能解決,不過事實證明我還是錯了。接下來將記錄下爬蟲中遇到的一些坑以及解決辦法。

開始

相關

目標網站:AVADA – Avada Commerce
使用了Cloudflare的cdn服務,而且Cloudflare又和百度有合作,所以我們的訪問異常時,就會被百度的雲加速服務給攔截下來。

亂碼問題

本來是準備用比較拿手的java寫此次爬蟲,java請求返回的內容總是出現一些亂碼的問題。已經設定為utf-8方式並且像gzip、br等解壓縮都嘗試了,稍微好點的情況只有body標籤內的內容為亂碼,糟糕的情況就是整個返回的內容皆為亂碼。後來就用python試了試,亂碼問題直接沒了,有點迷!

驗證碼問題

之前用python解決亂碼問題後,緊接著又出現的就是訪問需要驗證碼了。當時我是瀏覽器裡訪問不需要驗證碼,但python訪問不管如何,一直出現百度雲加速的驗證碼認證。出現這種情況,我的第一反應是python中是不是少了某些關鍵頭部,於是將瀏覽器中的header帶到python中一 一去試,但並沒有起到啥作用。這裡我就賊納悶了,究竟為甚嗎???後來才突然想起來我瀏覽器走了代理,於是我乾脆給電腦設定了個全域性代理,然後用python繼續訪問,讓人感動的一幕發生了-----> 命令列中返回了目標網站的頁面原始碼!這時我才察覺,我的本地IP已經進入了目標網站的黑名單 。到這裡,驗證碼也就繞過了。

JS導致頁面url發生重定向

在把前面的目標網站的頁面下載到本地後,然後用瀏覽器開啟該檔案,瀏覽器會載入頁面中的一些圖片css還有js等資原始檔,其中有個js會檢測當前頁面url中的協議是否是https,如果不是,將重定向至對應的https協議的頁面。這裡顯然,我們開啟的本地檔案url是檔案的目錄,不是以https開始的。
比如火狐瀏覽器中開啟目標檔案,位址列的url如下

file:///C:/Users/Asche/vscode/Shopify/temp/Customers/How%20to%20add%20or%20edit%20a%20customer%E2%80%99s%20address.html

被重定向後的url如下

https://c/Users/Asche/vscode/Shopify/temp/Customers/How%20to%20add%20or%20edit%20a%20customer%E2%80%99s%20address.html

顯然,重定向後的頁面是不存在的。當然,我們也可以在頁面重定向前手動取消重定向的請求,不過這樣畢竟體驗不好,所以繼續想辦法解決重定向問題。
於是,準備尋找起重定向作用的·js程式碼,瀏覽一番渲染後的頁面原始碼,發現在body標籤結束前,多了這樣一段程式碼:

<script type="text/javascript" id="">"https:"!=location.protocol&&(location.href="https:"+window.location.href.substring(window.location.protocol.length));</script>

而且這段程式碼在最初的頁面內是沒有的,說明是被別的js動態載入進來的。所以我就選擇其中的一段程式碼‘location.protocol‘,在其餘幾個可疑的js檔案內搜尋,遺憾的是沒有找到。
另外本來想使用js的debug功能,奈何一到dubug頁面,瀏覽器就未響應!!!
最後沒有辦法,我就直接在目標檔案上選擇性的註釋js引入,可疑的js檔案都被註釋掉了,卻發現任然存在重定向!!!最後,只剩下一個google相關的js,把那個js註釋掉,重定向終於消失了!那段js程式碼大概如下:

<script>(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','GTM-NPVH4QZ');</script>

本來以為這段程式碼就像google分析那樣的一些沒啥影響的Google服務,結果卻讓人有點意外!可能是出於安全的考慮把。
到這裡,重定向也解決!

主要部分Python程式碼

import requests
import os
from bs4 import BeautifulSoup

# Author: Asche
# date: 2019年7月6日
print('Shopify start...')

BASE_URL = 'https://avada.io'
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36',
           'Cookie': '__cfduid=db73a1a3b63a54e86f435f615f5ec37791562300679; _ga=GA1.2.1048718546.1562300686; _gid=GA1.2.312498482.1562300686',
           'Accept': '*/*', 'Accept-Encoding': 'gzip', 'Accept-Language': 'en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7,mt;q=0.6'}


def getHtml(url):
    req = requests.get(url, headers=headers)
    return req.text


def saveFile(name, dir, content):
    folder = os.path.exists(dir)
    if not folder:
        os.mkdir(dir)
    with open( dir + '/' + name.replace('/', '_') + '.html', 'w', encoding='utf-8') as f:
        f.write(content)


def crawlSubpage(url, dir):
        subPage = requests.get(url, headers=headers)
        # print(strHome.headers)

        soup = BeautifulSoup(subPage.content, 'lxml')
        print(soup.title)

        titles = soup.select('div.collection a')
        for title in titles:
            print(title.text, title['href'])
            saveFile(title.text, dir, getHtml(title['href']))


strHome = requests.get(BASE_URL, headers=headers)
# print(strHome.text)
print(strHome.headers)


soup = BeautifulSoup(strHome.content, 'lxml')
# print(soup.prettify)
print(soup.title)

titles = soup.select('h3.header a')
for title in titles:
    print(title.text, title['href'])
    crawlSubpage(title['href'], title.text)

相關文章