I.はじめに
Webクローラーは、WebスパイダーやWebロボットとも呼ばれ、特定のルールに従ってWorld Wide Web上の情報を自動的にクロールするプログラムまたはスクリプトです。いわゆるクロールデータは、ブラウザーをシミュレートしてインターネットをサーフィンし、それをブラウザーに渡してデータを取得するプログラムを作成するプロセスです。使用シナリオでのクローラーの分類:
- 一般的なクローラー:クロールシステムの重要な部分。フェッチされるのは、データのページ全体です。
- クローラーに焦点を当てる:一般的なクローラーに基づいて構築されています。クロールされるのはページの特定の部分です。
- インクリメンタルクローラー:Webサイトのデータの更新を検出します。Webサイトからの最新の更新データのみがクロールされます。
ポータルWebサイトの一部のデータにはプライバシーの問題が含まれている可能性があります。または、一部のクローラーがWebサイトに損傷を与えないようにするために、対応する戦略または技術的手段を指定して、クローラーがWebサイトデータをクロールできないように、対応するクロール防止メカニズムが確立されます。クライミング防止メカニズムが誕生したのとほぼ同時に、robots.txtアンチクライムプロトコルが誕生しました。robots.txtプロトコルは紳士のプロトコルであり、クロールできるWebサイトのデータとクロールできないデータを明確に規定しています。ウェブサイトのロボットのクライミング防止プロトコルを確認してください:ドメイン名/robots.txt。たとえば、バイドゥのロボットプロトコルを確認してください:https://www.baidu.com/robots.txt。アンチクライム機構により、アンチアンチクライムが誕生しました。関連する戦略または技術的手段を策定することにより、クローラープログラムはポータルWebサイトのアンチクライミングメカニズムをクラックして、ポータルWebサイトのデータを取得できます。
WWW上の情報をクロールしているため、最初にHTTPおよびHTTPSプロトコルを理解することは避けられません。HTTPプロトコルは、ハイパーテキスト転送プロトコル(Hyper Text Transfer Protocol)の略で、ハイパーテキストをWorld Wide Web(WWW:World Wide Web)サーバーからローカルブラウザに転送するために使用される転送プロトコルです。単純な理解とは、サーバーとクライアント間のデータ対話の一種です。HTTPSプロトコルはSecure Hyper Text Transfer Protocolの略で、HTTP上にSSL暗号化レイヤーを確立し、HTTPよりも安全なデータを暗号化します。2つの関係は、HTTPS = HTTP + TLS / SSLです。HTTPには情報の盗聴、改ざん、ハイジャックなどのリスクがありますが、HTTPSは情報の暗号化、整合性検証、ID検証を実行してリスクを軽減します。HTTPSの動作メカニズムとHTTPとの関係から、次の違いがあると結論付けることができます。
- 費用:HTTPSプロトコルは、caで証明書を申請する必要があります。一般的に、無料の証明書は少なく、一定の料金が必要です。
- 送信:HTTPはクリアテキストの送信方法ですが、HTTPSはセキュアなSSL暗号化送信プロトコルであるセキュアなハイパーテキスト送信プロトコルです。
- ポート:HTTPとHTTPSはまったく異なる接続方法を使用し、使用されるポートも異なります。前者はポート80を使用し、後者はポート443を使用します。
- セキュリティ:HTTP接続は非常にシンプルでステートレスですが、HTTPSプロトコルはSSL + HTTPで構成されたネットワークプロトコルであり、より高いセキュリティで暗号化および認証できます。
接続を確立するプロセスでは、データヘッダーに多くの重要な情報が含まれます。一般的なリクエストヘッダー情報:User-Agent:リクエストキャリアのID; Connection:ブラウザは、リクエスト後に切断するか接続を維持するかを、このヘッダーを通じてサーバーに伝えます。共通の応答ヘッダー情報:Content-Type:サーバーは、このヘッダーを介して送り返されるデータのタイプをブラウザーに通知します。
次に、データのクロール
ネットワークリクエストに関連するモジュールには、urllibモジュールとリクエストモジュールがありますが、後者はより簡潔で効率的ですが、現在は後者がより一般的に使用されています。データクロールでは、主にリクエストモジュールもここで使用されます。リクエストモジュールは、Pythonのネイティブネットワークリクエストベースのモジュールであり、非常に強力で、シンプルで便利に使用でき、クローラー操作をより効率的に処理できます。その機能は、ブラウザーをシミュレートして要求を送信し、ブラウザーを開いてWebページを要求することです。まず、要求URLをアドレスバーに入力し、Enterキーを押して要求を送信します。送信が正常に完了すると、ブラウザーは要求によって送信できる応答データ情報を表示します。 Webページ要求のコーディングのアイデアは次のとおりです。
- 指定url
- リクエストを送信
- 応答データを取得する
- 永続的なストレージ
以下は、より浅い方から深い方へクロールするデータについて説明しています。まず、例としてBaiduホームページ(www.baidu.com)のリクエストを取得し、requestsライブラリを使用してBaiduホームページをリクエストし、返された結果を印刷して、レスポンスデータをローカルに保存します。
# -*- coding:utf-8 -*-
import requests
# 需求:爬取百度网页的数据
if __name__ == '__main__':
# step1: 指定url
url = 'https://www.baidu.com/'
# step2: 发送求情
# get方法会返回一个响应数据
response = requests.get(url=url)
# step3: 获取响应数据
# .text返回字符串式的响应数据
page_text = response.text
print(page_text)
# step4: 持久化存储
with open('./baidu.html','w',encoding='utf-8') as fp:
fp.write(page_text)
print('爬取数据结束!')
上記のコードにより、応答百度ホームページのページデータを取得できます。もちろん、ほとんどの人にとって、ブラウザの重要な機能は情報を検索することです。ここでは、Webページを要求する例として検索キーワード「Hello」を取り上げます。
# -*- coding:utf-8 -*-
import requests
if __name__ == '__main__':
# UA伪装:将对应的User-Agent封装到一个字典中
headers = {
'User-Agent':'你的标识'
}
# step1: 指定url
url = 'https://www.sogou.com/web'
params = '你好'
# step2: 发送请求
response = requests.get(url=url,params=params,headers=headers)
# step3: 获取响应数据
page_text = response.text
# step4: 持久化存储
fileName = query+'.html'
with open(fileName,'w',encoding='utf-8') as fp:
fp.write(page_text)
print(fileName,'保存成功!')
上記のコードは、ブラウザーを開き、検索するキーワードを入力し、検索結果ページのデータ情報を返すことを実現します。前のコードとの違いは、1つはURLに添付されたパラメーターを設定することであり、もう1つはUA変装のヘッダー情報を設定することです。いわゆるUA、つまりUser-Agentは、リクエストキャリアのIDです。一部のポータルは、UA検出をクロール防止メカニズムとして使用し、サーバーはリクエストキャリアのIDを検出します。リクエストキャリアのIDが特定のブラウザーとして検出された場合、それは通常のリクエストと見なされ、それ以外の場合は検出されます。要求が特定のブラウザーに基づいていない場合、これはクローラープログラムなどの通常の要求ではないと見なされ、サーバーはアクセスを拒否し、クローラープログラムはデータのクロールに失敗します。したがって、ここにUser-Agentが設定され、リクエスト元のサーバーにこれが通常のリクエストであると思わせるために、UAの偽装が実行されます。
上記は、応答データをhtmlファイルとして保存することであり、jsonライブラリを介して応答データをjson形式のファイルとして保存することもできます。Baidu Translateを例にとります。翻訳コンテンツが入力されると、ページの部分的なコンテンツが更新されます。これはajaxテクノロジーです。応答データ情報を確認するには、->ネットワーク-> XHRをチェックします。XHRは、 Ajaxデータ要求は、応答データを受け取った後、それをjson形式のファイルとして保存します。エンコーディングは次のとおりです。
# -*- coding:utf-8 -*-
import requests
import json
if __name__ == '__main__':
# 1、指定url
url = 'https://fanyi.baidu.com/sug'
# UA伪装,设置请求载体标识
headers = {
'User-Agent':'你的标识'
}
# 参数处理
kw = input('请输入要翻译的文字:')
data = {
'kw':kw
}
# 2、发送请求
response = requests.post(url=url,data=data,headers=headers)
# 3、获取响应数据。json()方法返回一个json对象。
res_obj = response.json()
print(res_obj)
# 4、持久化存储
fileName = kw+'.json'
fp = open(fileName,'w',encoding='utf-8')
json.dump(res_obj,fp=fp,ensure_ascii=False)
print(kw+'翻译结果已存储!')
また、上記の2つのコードとは異なり、永続ストレージが実行されると、以前にwithキーワードが使用されていたにもかかわらず、それが直接fpに割り当てられます。withは、python2.5から導入された新しい文法です。これは、コンテキスト管理プロトコルです。目的は、try、except、およびfinalキーワードと、リソースの割り当てと解放に関連するコードをフローチャートから削除し、tryとexceptを簡素化することです、最後に処理フロー。基本的な構文形式は次のとおりです。withexp [as target]:with body。また、この例では、ページの一部のデータが動的に読み込まれる可能性が高いことがわかります。たとえば、上記のコードによって取得されたデータは動的であり、Webページのアドレスバーのアドレスを通じて取得されません。上記の例はすべて、Webページのデータを取得するためのURLに直接基づいています。Webサイトのデータの詳細データを取得する場合は、応答データの処理とWebページのリダイレクトが含まれる場合があります。たとえば、次の例:
# -*- coding:utf-8 -*-
import requests
import json
if __name__ == '__main__':
# get id
# designate home url
home_url = 'http://125.35.6.84:81/xk/itownet/portalAction.do?method=getXkzsList'
# dset headers
headers = {
'你的标识'
}
# store company id and personal name
id_list = []
person_list = []
# set paramenter
for page in range(1,6):
page = str(page)
params = {
"on": "true",
"page": page,
"pageSize": 15,
"productName":"",
"conditionType": 1,
"applyname":""
}
# initiate request
res_json = requests.post(url=home_url,data=params,headers=headers).json()
# print(res_json)
for dic in res_json['list']:
id_list.append(dic['ID'])
# print(id_list)
# start to access personal name according to id
# designate detail url
detail_url = 'http://125.35.6.84:81/xk/itownet/portalAction.do?method=getXkzsById'
# set detail paraments
for id in id_list:
access_detail_data = {
"id":id
}
#initiate request,and get detail response
detail_res = requests.post(url=detail_url,data=access_detail_data,headers=headers).json()
# test
person_list.append(detail_res['businessPerson'])
print(person_list)
# persistently store
fileName = 'personalname.txt'
fp = open(fileName,'w',encoding='utf-8')
json.dump(person_list,fp=fp,ensure_ascii=False)
print(fileName,'已完成存储!')
上記のコードは、食品医薬品局を通じて取得した化粧品会社の法定代理人を例に取り、ループを介してWebページの複数ページのデータをクロールし、クロールされたデータから必要な情報を抽出し、その情報に従って情報をアドレスにスプライスし、必要な情報をクロールします。最終的に詳細情報がカットされ、ローカルに保存されます。
3、データ分析
多くの場合、Webページ全体のデータではなく、Webページの有用な情報の一部が必要なので、取得したデータを処理し、必要な情報を分析または抽出する必要があります。データ分析の原則は、Webページの必要な部分的なテキストコンテンツがタグまたはタグの属性として格納されることです。対応するタグを見つけることにより、必要なテキストコンテンツをタグまたはタグの属性から解析できます。ここに3つの要約があります。形式:定期分析、bs4分析、xpath分析。一般に、データの分析は、永続ストレージの前と応答データの取得後に行われます。上記のデータクロールプロセスは、次のように拡張できます。
- 指定url
- リクエストを開始する
- 応答データを取得する
- データ分析
- 永続的なストレージ
以下では、正規表現bs4とxpathを使用して分析する3つの例を通じて、データ分析を紹介します。
1.定期的な分析
次のポストバー背景画像のクロールの例から、前のデータクロールプロセスと比較して、もう1つのデータ分析プロセスがあることがわかります。応答データは、指定されたページへの要求を開始することによって取得され、その後、応答データが解析され、正規表現でフィルター処理されます。 、必要な画像アドレスデータを取得し、最後に、取得した画像アドレスデータに従って画像を取得する要求を開始し、ローカルフォルダーに保存します。Pythonの正規分析の原則は、reモジュールをインポートし、対応する正規表現を設定し、findallメソッドを呼び出して、要求された応答データを照合し、要件を満たすデータを除外することです。python1.5バージョン以降、perlスタイルの正規表現を提供するreモジュールが追加されました。これにより、Python言語ですべての正規表現関数を使用できるようになります。以下のコードでは、対応する正規表現を保存するためにex変数が定義されています。「。」は改行を除くすべての文字、「*」は任意の回数、「?」はオプション、findllメソッドを意味しますこの記事の内容を正規表現と一致させるために、修飾子re.Iに加えて、複数行マッチングの修飾子re.Mを次に示します。解析では、修飾子re.Mが一般的に使用されます。これは、必要に応じて特定され、複数の修飾子を同時に使用して、一致モードを制御できます。これは、大文字と小文字を区別せずに一致させる場合、ビット単位のOP(|)によって実現されます。行データの場合、IフラグとMフラグの両方が設定されます(re.I | re.M)。さらに、他にも多くのオプションのモードと修飾子があります。Python正規表現を参照してください。
# -*- coding:utf-8 -*-
import requests
import re
import os
if __name__ == '__main__':
# 指定url
url = 'https://tieba.baidu.com/p/6469380781'
# 伪装UA
headers = {
'User-Agent': '你的标识'
}
# 发起请求
res_text = requests.get(url=url,headers=headers).text
# print(res_text)
# 使用聚焦爬虫对网页的数据进行解析或者提取
ex = '<img class="BDE_Image" src="(.*?)" .*?><br>'
img_list = re.findall(ex,res_text,re.S)
# print(img_list)
# 创建文件夹,保存数据
if not os.path.exists('./touxiang'):
os.mkdir('./touxiang')
for img in img_list:
# 获取图片数据
img_data = requests.get(url=img,headers=headers).content
# 设置图片名称
img_name = img[-10:]
# 将图片保存至本地
img_path = './touxiang/'+ img_name
with open(img_path,'wb') as fp:
fp.write(img_data)
print(img_name,'已成功下载!')
2、bs4分析
上記の通常の分析方法は、python言語だけでなく他の言語でも使用でき、より一般的なデータ分析方法です。また、bs4はpython言語独自のデータ解析手法であり、python言語でのみ使用できます。この解析方法では、lxmlパーサーとBeautifulSoupオブジェクトのインスタンス化が必要であるため、データ分析にbs4を使用する場合は、環境にbs4モジュールとlxmlモジュールをインストールする必要があります(pip install bs4およびpip install lxml)。分析の原則は、BeautifulSoupオブジェクトをインスタンス化し、解析するデータをオブジェクトにロードしてから、BeautifulSoup関連の属性またはメソッドを呼び出してデータを見つけるか、データを抽出することです。BeautifulSoupオブジェクトに読み込まれた解析済みデータは、ローカルファイルまたはWebからクロールされたファイルから取得できます。前者の場合、ローカルファイルをopen関数で開き、BeautifulSoupオブジェクトに読み込むことができます:soup = BeautifulSoup(open( 'local file to be parsed')、 'lxml');後者の場合、クロールされたネットワークデータが渡されます。テキストメソッドは文字列オブジェクトのデータに変換され、BeautifulSoupオブジェクトに読み込まれます。soup= BeautifulSoup( '解析されるWebページデータ'、 'lxml')。オブジェクトをロードした後、必要に応じてラベルの配置またはデータ抽出を実行します。
- 配置タグ:soup.tagName。たとえば、soup.a。
- 属性の取得:soup.tagName.attrsは、タグのすべての属性を含む辞書を返します。イメージ名を取得するには:soup.img.attrs ['alt']またはsoup.img ['alt']。
- コンテンツを取得:soup.tagName.text、soup.tagName.string、soup.tagName.get_text。文字列メソッドはタグの下のダイレクトテキストコンテンツのみを取得でき、他の2つはタグ内のすべてのテキストコンテンツを取得できます。
- 要件を満たすタグを見つけます:soup.find( 'tagName' [、title = "" / alt = "" / class _ = "" / id = ""])。
- 要件を満たすすべてのタグを検索します。soup.find_all( 'tagName')はすべてのtagNameタグを返します。soup.find_all( 'tagName1'、 'tagName1')はすべてのtagName1およびtagName2タグを返します。soup.find_all( 'tagName'、limit = 2)最初の2つのラベルに戻ります。
- セレクターに従って指定されたコンテンツを選択します。soup.select( 'tag_name / .class_name /#id_name / level selector')はリストを返します。レベルセレクターには、「>」と「」を使用できます。前者は1つのレベルを表し、後者は複数のレベルを表します。
# -*- coding:utf-8 -*-
import requests
from bs4 import BeautifulSoup
if __name__ == '__main__':
# step1: 爬取章节页面的数据
# 伪装UA
headers = {
'User-Agent': '你的标识'
}
# 指定url
chapter_url = 'http://www.shicimingju.com/book/hongloumeng.html'
# 发起请求
chapter_text = requests.get(url=chapter_url,headers=headers).text
# step2: 对章节页面的数据进行解析,获得章节标题和详情页的url,并将爬取的数据保存至本地
# 实例化beautifulsoup对象,把章节页面的源码数据加载到该对象中
chapter_soup = BeautifulSoup(chapter_text,'lxml')
# print(chapter_soup)
chapter_list = chapter_soup.select('.book-mulu > ul > li')
fp = open('./红楼梦.txt','w',encoding='utf-8')
for li in chapter_list:
# 获得详情页的url、章节标题
detail_url = 'http://www.shicimingju.com'+li.a['href']
chapter_title = li.a.string
# 请求详情页,获得章节详细内容
detail_text = requests.get(url=detail_url,headers=headers).text
# 对详情页的数据进行解析,获得每个章节的具体内容
detail_soup = BeautifulSoup(detail_text,'lxml')
detail_content = detail_soup.find('div',class_='chapter_content').text
fp.write(chapter_title+':'+detail_content)
print(chapter_title,'下载完成!')
3. Xpath分析
Xpath解析は、最も汎用的に使用され、強力で汎用性のある最も便利で効率的な解析方法です。この解析方法には、上記のbs4と多くの類似点があります。まず、この解析にはlxmlパーサーが必要であり、etreeモジュールを使用してetreeオブジェクトをインスタンス化するため、環境をインストールする必要があります:pip install lxml。この解析方法の原則は、etreeオブジェクトをインスタンス化し、解析するソースコードデータをetreeオブジェクトにロードし、epathでxpathメソッドとxpath式を呼び出して、ラベル配置と指定されたデータ抽出を実装することです。etreeに読み込まれたオブジェクトは、2つのカテゴリに大別することもできます。1つはローカルファイルデータで、もう1つはクロールされたネットワークデータです。ローカルファイルの場合は、parseメソッドを呼び出してetreeオブジェクトをインスタンス化します。tree = etree.parse(文件名);如是通用爬虫爬取的网络源码,使用.text将网页源码数据转化为字符串内容,再调用HTML方法加载到etree对象中:tree = etree.HTML(网页内容字符串)。实例化etree对象后,通过 xpath表达式、调用xpath方法进行标签定位和数据提取,常见的xpath表达式如下:
- / ルートノードから配置を開始し、1つのレベルを示します; // 複数のレベルを示し、任意の位置から配置を開始できます。
属性定位://div[@class="class_name"]。找到class属性值为class_name的div标签。
- レベルとインデックスの配置://
div[@class="class_name"]/tag1/tag2[1]/tag3。找到class属性值为class_name的div直系子标签tag1下的第一个自标签tag2下的直系自标签tag3。
- 属性を取る://
div[@class="class_name"]//tag1[3]/a/@href。获取class属性值为class_name的div的第三个直系自标签下的a标签的href属性值。
- テキストを取る://
div[@class="class_name"]/text(),获取class属性值为class_name的div的直系文本内容;
//div[@class="class_name"]//text(),获取class属性值为class_name的div标签中的所有文本内容。
- あいまい一致:
//div[contains(@class, "ng")]
クラス属性値にngを含むdivタグを見つけます。//div[starts-with(@class, "ta")],找到class属性值以ta开头的div标签
- 論理演算:// a [@ href = ""および@ class = "du"]で、href値が空でクラス値がduであるタグを見つけます。
# -*- coding:utf-8 -*-
import requests
from lxml import etree
import os
if __name__ == '__main__':
# step1: 获取图片所在网页的源码数据
# 伪装UA
headers = {
'User-Agent': '你的标识'
}
# 指定url
url = 'http://pic.netbian.com/4kfengjing/'
# 发起请求
home_text = requests.get(url=url,headers=headers).text
# print(home_text)
# step2: 对获取的源码数据进行解析
home_etree = etree.HTML(home_text)
li_list = home_etree.xpath('//div[@class="slist"]/ul/li')
# step3: 创建文件夹,保存下载的图片文件
if not os.path.exists('./风景图'):
os.mkdir('./风景图')
# print(li_list)
for li in li_list:
# 获取图片的地址和名称
img_url = 'http://pic.netbian.com'+li.xpath('./a/img/@src')[0]
img_name = li.xpath('./a/img/@alt')[0].encode('iso-8859-1').decode('gbk')+'.jpg'
# print(img_name)
# 访问图片地址,获取图片数据
img_content = requests.get(url=img_url,headers=headers).content
# 对获取的图片进行持久化存储
save_path = './风景图/'+img_name
with open(save_path,'wb') as fp:
fp.write(img_content)
print(img_name,'下载成功!')
参考資料:
1. 初心者向けチュートリアル
2. リトルエイプサークル
3. クローラー開発の開始