記事ディレクトリ
これは Python クローラーの入門演習であり、Request を通じてデータを要求し、XPath を通じてテーブル内の要素またはコンテンツを照合し、Pandas を使用してデータを整理します。これを段階的に実行してみましょう。
目標の決定とアイデアの分析
目標
目標は、Web サイトから表形式のデータを収集することです。私が選んだサイトは次のとおりですhttp://py.ucas.ac.cn/zh-cn/zhuanjia/ZhuanjiaList
(以下はリスト ページと呼ぶこともできます)。
- ここにはリスト ライブラリがあり、名前やユニット名などの個人情報が含まれています。
- リストは複数のページに分かれており、詳細情報を読み込むには次のページをクリックし続ける必要があります。
- 詳細については、リスト上の名前をクリックしてサブページ (以下、詳細ページと呼びます) に入り、表示する必要があります。循環クリックと二次的なクロールが必要です。
一連の考え
そのアイデアは、XPath の選択とリスト ページでのページめくりを通じて、各人物に対応するすべての詳細ページのリンクを取得するというものです。次に、詳細ページのリンクをたどって情報をクロールし、csv ファイルとして保存します。
状況を観察する
F12 を押してブラウザの開発者ツールを開き、[ネットワーク] ページを選択します。
リスト ページを更新すると、リクエスト URL やリクエスト ヘッダーなどの情報フローが表示されます。パスワードログインのため、リクエスト送信時のヘッダ情報としてCookieが必要です。
リスト ページの 2 ページ目をクリックすると、ページをめくるには、URL リンク page=: 以降のコンテンツを変更するだけで済むことがわかりましたhttp://py.ucas.ac.cn/zh-cn/zhuanjia/ZhuanjiaList?pinqing_dwdm=80002&is_yw=False&page=xxx
。
ネットワーク情報フローをクリアし、任意の名前をクリックして、名前の変更に対応する詳細ページを開きます。そのリクエスト URL が次であることを確認しますhttp://py.ucas.ac.cn/zh-cn/zhuanjia/ZhuanjiaEdit?zhuanjia_id=xxxxx
。get という形式で情報を要求しており、zhuanjia_id は各人の ID に対応しており、ID が変更されていれば別の人の情報が返されます。一覧ページの名前欄のhrefにID情報があることが分かります。
試してみたところ、オンラインテーブルの読み込みや基本的なデータの整形操作をpandasのpandas.read_htmlで行うのは面倒なので、XPathを直接使って検索しています。
クロールリストテーブル
上記の考え方に従い、まず一覧ページを利用し、ページをめくって全員に対応する詳細ページに情報をまとめるという2ステップで進めていきます。観察できるのは、
ヘッダーを書き込んだ後、requests.get を通じて Web ページ情報を返し、Xpath を使用して抽出およびアーカイブします。
コードは以下のように表示されます。
import requests
from lxml import etree
import pandas as pd
# parameter = {
# "key1":"value1",
# "key2":"value2"
# }
headers = {
"Cache-Control": "max-age=0",
"Connection":"keep-alive",
"Cookie":"xxxxxxxxxx",
"Referer":"http://py.ucas.ac.cn/zh-cn/zhuanjia/ZhuanjiaList?pinqing_dwdm=80002&is_yw=False&page=2",
"Upgrade-Insecure-Requests":"1",
"User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36"
}
total_page = 2111
dfs = pd.DataFrame(columns=['name','id']);
ind = 0
for i in range(2111,total_page+1):
response = requests.get("http://py.ucas.ac.cn/zh-cn/zhuanjia/ZhuanjiaList? \
pinqing_dwdm=80002&is_yw=False&page="+str(i), \
headers = headers)#,params = parameter)
# print(response.url)
# print(response.text)
# print(response.content)
# print(response.encoding)
# print(response.status_code)
html=response.text
tree=etree.HTML(html)
NAME = tree.xpath('//*[@id="main-content"]/div/div/div/div/div[2]/div/table/tbody/tr/td[1]/a')
IDHREF = tree.xpath('//*[@id="main-content"]/div/div/div/div/div[2]/div/table/tbody/tr/td[1]/a/@href')
for j in range(0,len(NAME)):
ind = ind+1
print(ind)
ids = str(IDHREF[j]).split('=')
new = pd.DataFrame({
'name':NAME[j].text, 'id':int(ids[1])},index=[ind])
dfs=dfs.append(new)
dfs.to_csv("./教授名字和ID.csv", encoding="utf_8_sig")
特に強調することはありませんが、このコードはそれほど高性能ではなく、tree.xpath が 1 つしかないなど、最適化できる箇所が多数あります。
詳細ページの二次情報をクロールする
詳細ページをクロールするために必要なIDを取得できたと仮定すると、この時点で少しずつ異なるURLにリクエストを送信し続けることで、すべての詳細ページの情報を取得できます。次に、開発者ツールで XPath コピー ツールを右クリックして XPath マッチング モードを取得し、情報を貼り付けて抽出し、Pandas で整理してアーカイブします。使用されるコードは次のとおりです。
import requests
from lxml import etree
import pandas as pd
ID1 = pd.read_csv('./教授名字和ID0.csv')
ID2 = pd.read_csv('./教授名字和ID.csv')
ID1n = list(map(int, ID1['id']))
ID2n = list(map(int, ID2['id']))
IDs = ID1n+ID2n
IDs.sort()
header = {
"Connection": "keep-alive",
"Cookie": "xxxx",
"Host": "py.ucas.ac.cn",
"Referer": "http://py.ucas.ac.cn/zh-cn/zhuanjia/ZhuanjiaList?pinqing_dwdm=80002&is_yw=False&page=1936",
"Upgrade-Insecure-Requests": "1",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36"
}
bg = 20617;
ed = len(IDs)
#ed = 2
data = pd.DataFrame(columns=['姓名','性别','单位','通讯地址','邮编','邮箱','手机',\
'固话','出生日期','身份证号','学科专业','方向','导师类别',\
'专业技术职务','银行户头','银行地址','银行号码'])
count = -1
for i in range(bg,ed):
count = count+1
id = IDs[i]
print(str(IDs[bg])+"TO"+str(IDs[ed-1])+":"+str(i)+":"+str(id)+"进行中...")
response = requests.get("http://py.ucas.ac.cn/zh-cn/zhuanjia/ZhuanjiaEdit?zhuanjia_id="+str(id),headers=header)
html=response.text
# print(html)
# with open('test.html','w',encoding='utf-8') as f:
# f.write(html)
tree=etree.HTML(html)
zjxm = str(tree.xpath('//*[@id="ZJXM"]/@value')[0]) #姓名
zjxb = str(tree.xpath('//*[@id="ZJXB"]/option[@selected="selected"]/@value')[0])#性别
jsdw = str(tree.xpath('//*[@id="DWDM"]/option[@selected="selected"]')[0].text)#单位
zjtxdz = str(tree.xpath('//*[@id="ZJTXDZ"]/@value')[0])#通讯地址
zjyzbm = str(tree.xpath('//*[@id="ZJYZBM"]/@value')[0])#邮编
UserName = str(tree.xpath('//*[@id="UserName"]/@value')[0])#邮箱
zjsj = str(tree.xpath('//*[@id="ZJSJ"]/@value')[0])#手机
zjtel = str(tree.xpath('//*[@id="ZJTEL"]/@value')[0])#固话
zjcsrq = str(tree.xpath('//*[@id="ZJCSRQ"]/@value')[0])#出生日期
zjhm = str(tree.xpath('//*[@id="zjhm"]/@value')[0])#身份证号
tmp = tree.xpath('//*[@id="ZJ_XKZY"]/option[@selected="selected"]')
if len(tmp)==0:
zjxkzy = ''
else:
zjxkzy = str(tmp[0].text)#学科专业
yjfx = str(tree.xpath('//*[@id="yjfx"]/@value')[0])#方向
zjlb = str(tree.xpath('//*[@id="ZJLB"]/option[@selected="selected"]')[0].text)#导师类别
tmp = tree.xpath('//*[@id="ZJZWCODE"]/option[@selected="selected"]')
if len(tmp)==0:
zjzwcode = ''
else:
zjzwcode = str(tmp[0].text)#专业技术职务
bank_hutou = str(tree.xpath('//*[@id="bank_hutou"]/@value')[0])#银行户头
bank_dizhi = str(tree.xpath('//*[@id="bank_dizhi"]/@value')[0])#银行地址
bank_xingming = str(tree.xpath('//*[@id="bank_xingming"]/@value')[0])#银行号码
data.loc[count] = [zjxm,zjxb,jsdw,zjtxdz,zjyzbm,UserName,zjsj,zjtel,zjcsrq,zjhm,zjxkzy,yjfx,zjlb,zjzwcode,bank_hutou,bank_dizhi,bank_xingming]
data.to_csv("./"+str(bg)+"_"+str(IDs[bg])+"TO"+str(i)+"_"+str(IDs[i])+"高校教授联系方式.csv", encoding="utf_8_sig")
長時間クロールすると、ネットワークの拒否など、常に何らかの問題が発生することがわかっています。私のコードでは、try モードでの例外キャプチャはありません。私が採用した例外処理方法では、コードが壊れてしまい、最初に中間結果を手動で保存していました。次に、ブレークポイントからコードの再実行を手動で開始します。
例外処理機構のないマニュアルトランスミッションのプロセスを楽しんでいます。
爬虫類の方は法令を遵守し、違法行為・犯罪行為は行わないでください。
爬虫類のこともよく書かれていて、食べ放題です。個人データをクロールしたり、Web サイトをクラッシュさせたりしないでください。営利を目的としてクローラー方式を使用しないでください。
クローラーのヒントのまとめ
-
リクエストのヘッダー情報は、ブラウザー開発者ツール情報ストリームから直接コピーして変更できます。
-
情報を照合する場合は、ブラウザーでリクエスト アドレスに直接アクセスし、返された結果に基づいて要素の照合を行うのではなく、Python リクエストによって返された Web ページを分析用に保存することをお勧めします。Python リクエストで得られる結果がブラウザリクエストで得られる結果と異なる場合があるためです。Python から返された Web ページの結果を保存するコード例は次のとおりです。
response = requests.get("http://py.ucas.ac.cn/zh-cn/zhuanjia/ZhuanjiaEdit?zhuanjia_id="+str(id),headers=header) html=response.text print(html) with open('test.html','w',encoding='utf-8') as f: f.write(html)
-
マウスの右ボタンで要素をチェックし、XPath をコピーして XPath 一致パターンを取得し、コード インターフェイスに貼り付けます。ただし、検索結果が空であるか間違っている場合は、比較や分析のために探している要素の姉妹ユニットに XPath をコピーできます。
-
XPath @ 関数が得意。XPath にアクセスしてラベル内の要素の値を取得するときは、@ を使用して値を取得できます。たとえば、
tree.xpath('//*[@id="DWDM"]/option[@selected="selected"]')[0].text
ここで角括弧はインデックスを表します。option[@selected="selected"]
これは、すべてのオプションの条件を満たすものを選択することを意味します (ここではドロップダウン ボックスによって生成されます)。別の例は /@value ですtree.xpath('//*[@id="ZJXM"]/@value')[0]
。これは、//*[@id="ZJXM"]
すべての value の値を取得してリストを形成することを意味します。 -
Request+XPath テンプレートを次のように整理します。何かをクロールするたびに、それをコピーして変更して使用します。
import requests from lxml import etree import pandas as pd # parameter = { # "key1":"value1", # "key2":"value2" # } header = { "Connection": "keep-alive", "Cookie": "xxx", "Host": "py.ucas.ac.cn", "Referer": "http://py.ucas.ac.cn/zh-cn/zhuanjia/ZhuanjiaList?pinqing_dwdm=80002&is_yw=False&page=1936", "Upgrade-Insecure-Requests": "1", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/107.0.0.0 Safari/537.36" } data = pd.DataFrame(columns=['姓名','单位']) response = requests.get("http://py.ucas.ac.cn/zh-cn/zhuanjia/ZhuanjiaEdit?zhuanjia_id=xxx",headers=header)#,params = parameter) html=response.text print(html) # print(response.url) # print(response.text) # print(response.content) # print(response.encoding) # print(response.status_code) with open('test.html','w',encoding='utf-8') as f: f.write(html) tree=etree.HTML(html) zjxm = str(tree.xpath('//*[@id="ZJXM"]/@value')[0]) #姓名 jsdw = str(tree.xpath('//*[@id="DWDM"]/option[@selected="selected"]')[0].text)#单位 data.loc[0] = [zjxm,jsdw] data.to_csv("xxx.csv", encoding="utf_8_sig")