1. タスクの要件
URL ホームの Web サイトのランキング情報をクロールし、画像 2 つとテキスト文字列 4 つの合計 6 つの指標を取得します。Web
ページは合計 30 あり、合計 10 ページをクロールする必要があることがわかります。は PNG ディレクトリに保存され、テキスト情報は info.txt ファイルに保存され、最終的に Linux 上の Mysql データベースにアップロードされます。
2. 実際のコード
import requests
import os,sys
import shutil
from bs4 import BeautifulSoup
import pymysql
conn=pymysql.connect(
host='192.168.1.111',
user='root',
passwd='root',
db='test',
port=3306
)
cursor=conn.cursor()
#爬第一个页面
response = requests.get(url="https://top.chinaz.com/hangye/")
def get_resource_path(relative_path): # 利用此函数实现资源路径的定位
if getattr(sys, "frozen", False):
base_path = sys._MEIPASS # 获取临时资源
print(base_path)
else:
base_path = os.path.abspath(".") # 获取当前路径
return os.path.join(base_path, relative_path) # 绝对路径
if response.status_code == 200: #404和405
print("连接成功!")
# 设置返回源码的编码格式
response.encoding = "UTF-8"
# print(type(response.text))
html = BeautifulSoup(response.text,"html5lib")
ul=html.find("ul",attrs={
"class":"listCentent"})#找唯一的父节点再找子节点,或者找出后得到列表取第一个
li_list = ul.find_all("li")
i = 0
PNG1=get_resource_path('png1') #判断是否有PNG目录存在,存在则删除再创建,避免使用的时候报错
if os.path.exists(PNG1):
shutil.rmtree(PNG1)
png1 = os.mkdir(PNG1)
PNG2=get_resource_path('png2') #判断是否有PNG目录存在,存在则删除再创建,避免使用的时候报错
if os.path.exists(PNG2):
shutil.rmtree(PNG2)
png2 = os.mkdir(PNG2)
PNG3=get_resource_path('png3') #判断是否有PNG目录存在,存在则删除再创建,避免使用的时候报错
if os.path.exists(PNG3):
shutil.rmtree(PNG3)
png3 = os.mkdir(PNG3)
for li in li_list:
i += 1
img_src1 = 'https:'+li.find_all("img")[0]["src"]
response_child1 = requests.get(img_src1)
fileWriter = open(get_resource_path(os.path.join("png1", "{}.png".format(i))), "wb")
fileWriter.write(response_child1.content)
img_src2 = 'https://top.chinaz.com'+li.find_all("img")[1]["src"]
response_child2 = requests.get(img_src2)
fileWriter1 = open(get_resource_path(os.path.join("png2", "{}.png".format(i))), "wb")
fileWriter1.write(response_child2.content)
img_src3 = 'https://top.chinaz.com'+li.find_all("img")[2]["src"]
response_child3 = requests.get(img_src3)
fileWriter2 = open(get_resource_path(os.path.join("png3", "{}.png".format(i))), "wb")
fileWriter2.write(response_child3.content)
name=li.find("a",attrs={
"class":"pr10 fz14"}).text
web=li.find("span",attrs={
"class":"col-gray"}).text
p_list=li.find_all("p",attrs={
"class":"RtCData"})
AleaxaRank=p_list[0].find('a').text
ReChainNum=p_list[3].find('a').text
text=open('info.txt','a',encoding='utf-8')
if i==1:
text.write('网站名'+' '+'网址'+' '+'Aleaxa排名'+' '+'反链数'+'\n')
else:
text.write(name+' '+web+' '+AleaxaRank+' '+ReChainNum+'\n')
text.close()
cursor.execute(
#"create table webs(name varchar(50),web varchar(50),AleaxaRank varchar(50),ReChainNum varchar(50),img_src1 varchar(200),img_src2 varchar(200))"
"insert into webs(name,web,AleaxaRank,ReChainNum,img_src1,img_src2)values(%s,%s,%s,%s,%s,%s)",
(str(name),str(web),str(AleaxaRank),str(ReChainNum),str(img_src1),str(img_src2))
)
conn.commit()#提交
#爬剩下的9个页面
for j in range(0,9):
div_a_list=html.find("div",attrs={
"class":"ListPageWrap"})
a_list=div_a_list.find_all('a')
website='https://top.chinaz.com'+a_list[j+2]["href"]
response = requests.get(url=website,timeout=(3,7)) #防止[WinError 10060] 由于连接方在一段时间后没有正确答复或连接的主机没有反应,连接尝试失败。
if response.status_code == 200: #404和405
print("连接成功!")
# 设置返回源码的编码格式
response.encoding = "UTF-8"
# print(type(response.text))
html = BeautifulSoup(response.text,"html5lib")
ul=html.find("ul",attrs={
"class":"listCentent"})#找唯一的父节点再找子节点,或者找出后得到列表取第一个
li_list = ul.find_all("li")
for li in li_list:
i += 1
img_src1 = 'https:'+li.find_all("img")[0]["src"]
response_child1 = requests.get(img_src1)
fileWriter = open(get_resource_path(os.path.join("png1", "{}.png".format(i))), "wb")
fileWriter.write(response_child1.content)
img_src2 = 'https://top.chinaz.com'+li.find_all("img")[1]["src"]
response_child2 = requests.get(img_src2)
fileWriter1 = open(get_resource_path(os.path.join("png2", "{}.png".format(i))), "wb")
fileWriter1.write(response_child2.content)
img_src3 = 'https://top.chinaz.com'+li.find_all("img")[2]["src"]
response_child3 = requests.get(img_src3)
fileWriter2 = open(get_resource_path(os.path.join("png3", "{}.png".format(i))), "wb")
fileWriter2.write(response_child3.content)
name=li.find("a",attrs={
"class":"pr10 fz14"}).text
web=li.find("span",attrs={
"class":"col-gray"}).text
p_list=li.find_all("p",attrs={
"class":"RtCData"})
AleaxaRank=p_list[0].find('a').text
ReChainNum=p_list[3].find('a').text
text=open('info.txt','a',encoding='utf-8')
if i==31:
text.write('网站名'+' '+'网址'+' '+'Aleaxa排名'+' '+'反链数'+'\n')
else:
text.write(name+' '+web+' '+AleaxaRank+' '+ReChainNum+'\n')
text.close()
cursor.execute(
"insert into webs(name,web,AleaxaRank,ReChainNum,img_src1,img_src2)values(%s,%s,%s,%s,%s,%s)",
(str(name),str(web),str(AleaxaRank),str(ReChainNum),str(img_src1),str(img_src2))
)
conn.commit()#提交
else:
print("连接失败!")
3. ステップ分析
<ul class="listCentent"> ##唯一listCentent,获取后得到列表
<li class="clearfix LCliTheOne"> #第一个li
<div class="leftImg">
<a name="obj_1" target="_blank" id="obj_1" href="/site_www.baidu.com.html">
<img src="//topimg.chinaz.net/WebSiteimages/baiducom/969e383d-19b6-4081-b933-a38ca415dd8a_2017_s.png" onerror="this.src='//topimg.chinaz.net/WebSiteimages/nothing.png'" alt="">
</a> ##从leftImg里面的img获取src图片1
</div>
<div class="CentTxt">
<h3 class="rightTxtHead">
<a href="/site_www.baidu.com.html" title="百度" target="_blank" class="pr10 fz14">百度</a> ##从rightTxtHead中的pr10 fz14获取百度
<span class="col-gray">www.baidu.com</span> ####从rightTxtHead中的col-gray获取www.baidu.com
</h3>
div class="RtCPart clearfix">
<p class="RtCData">
<span>Alexa周排名:</span>
<a target="_blank" href="//alexa.chinaz.com/www.baidu.com">4</a> ##从RtCData里的a中获得4
</p>
<p class="RtCData">
<span>百度权重为:</span> ##从RtCData中的a的img获得/images/baidu/9.gif
<a target="_blank" href="//rank.chinaz.com/www.baidu.com"><img src="/images/baidu/9.gif"></a>
</p> ##同理
<p class="RtCData"><span>PR:</span><a target="_blank" href="//pr.chinaz.com/?PRAddress=www.baidu.com"><img src="/images/ranks/Rank_9.gif"></a></p>
<p class="RtCData"><span>反链数:</span><a target="_blank" href="//outlink.chinaz.com/?h=www.baidu.com">345762</a></p>
</div>
<p class="RtCInfo">网站简介:百度,全球大的中文搜索引擎、大的中文网站。2000年1月创立于北京中关村。...</p>
</div>
<div class="RtCRateWrap">
<div class="RtCRateCent">
<strong class="col-red02">1</strong>
<span>得分:4999</span>
</div>
</div>
</li>
Ⅰ. 最初の Web ページの画像とテキストを取得します。
取得するデータはすべて ul の class="listCentent" タグの下にあり、クラス名は一意であることがわかります。そのため、find を使用して直接検索できます。 ul. 次に、find_all を使用して 30 の Web サイトのランキングを収集する li リストを見つけます。
メンバー ループを使用してリストを走査します。各ループで、最初に img を見つけて 3 枚の写真のリストを取得し、添え字の順序に従って 0 と 2 を指定します。つまり、目的のデータが取得されます。Web
サイト名については、その a タグに対応するクラス名 pr10 fz14 も一意であるため、find で直接見つけることができます。残りの 3 つのテキスト情報はすべて
p タグの下にあります、クラス名はすべて RtCData なので、直接 find_all でリストを検索し、目的のデータを取得します。
Ⅱ. ファイル ディレクトリの作成と書き込み:
PNG ディレクトリの場合は、クローラーを開始する前にファイル パスの場所を使用して現在のパスを取得し、ディレクトリを作成する必要があります。画像を書き込む場合は、ファイルの名前を追加する必要があります。 、カウンタとフォーマット形式を使用して比較します。ファイル名はネーミングで記述されます。プログラムを起動するたびに、PNG ディレクトリが存在するかどうかを確認する必要があります。存在する場合は削除して、プログラムの実行性を向上させます
。テキストファイルの作成は直接開くだけです追記モードを使用しないとループ内で毎回削除されてしまいます前回の書き込みの上書きや削除も事前に判定できます
Ⅲ. Mysql 接続と書き込み
conn=pymysql.connect(
host='192.168.1.111', #linux 対応 IP アドレス
user='root', #mysql ユーザー名
passwd='root', #mysql ログインパスワード
db='test' , #mysql データベース
ポート=3306 #mysql ポート番号
)
カーソル=conn.cursor() #カーソルを作成します
cursor.execute(
“webs(name,web,AleaxaRank,ReChainNum,img_src1,img_src2) 値に挿入します(%s,%s) ,%s,%s,%s,%s)", (
str(name),str(web),str(AleaxaRank),str(ReChainNum),str(img_src1),str(img_src2)) ) #前提
条件挿入するには、mysql に webs テーブルがあるということです。そうでない場合は、create table webs(name varchar(50), web varchar(50), AleaxaRank varchar(50), ReChainNum varchar(50), img_src1 varchar( 200), img_src2 varchar(200)), なぜmysql上で実行することを推奨しているのかというと、ライブラリが既に存在しているとプログラムを実行するたびにエラーが発生するからです。もちろん、先に判断することもできますし、最初の部分を使い切って一度コメントアウトします
。
Ⅳ. ウェブサイトのページめくりや不完全な URL の解決策
<div class="ListPageWrap">
<a href="/hangye/index.html" >
< </a><a class="Pagecurt"href="/hangye/index.html">1</a>
<a href="/hangye/index_2.html">2</a>
<a href="/hangye/index_3.html">3</a>
<a href="/hangye/index_4.html">4</a>
<a href="/hangye/index_5.html">5</a>
<a href="/hangye/index_6.html">6</a>
<a href="/hangye/index_7.html">7</a>
<a href="/hangye/index_8.html">8</a>
<span>...</span>
<a href="/hangye/index_1872.html">1872</a>
<a href="/hangye/index_2.html"> > </a>
</div>
ページめくりに対応する HTML コードを見つけて、div に対応するクラス「ListPageWrap」名が一意であることを確認します。そのため、場所を直接見つけることができます。次に、find_all を使用して a のリスト コレクションを取得し、for ループを使用して、各 Web ページの URL
また、この Web ページのジャンプにはすべて、index_ の後の数字 + 1 が続くことが観察されるため、for ループとフォーマット形式を使用して文字列を結合し、Web サイトを取得することもできます。
href または不完全な src URL を取得するには、それが規則的であれば、観察して文字列を結合します。規則的なパターンがない場合は、クリックをシミュレートすることによってのみ実現できます。
4. MySQL ビューの結果
mysql -uroot -proot
使用テスト;
Web から * を選択します。