基本操作流程:
- 首先辣恋,要明確要爬取某個網(wǎng)站的數(shù)據(jù)亮垫,此時若有多個鏈接地址解幼,則存入到URL列表進(jìn)行統(tǒng)一爬取包警;
- 接著撵摆,就是爬網(wǎng)站的數(shù)據(jù)內(nèi)容了,通常爬的數(shù)據(jù)內(nèi)容一般是網(wǎng)頁源代碼害晦;
- 當(dāng)爬下了數(shù)據(jù)特铝,就需要使用Python爬蟲技術(shù)進(jìn)行提取有價值的數(shù)據(jù)內(nèi)容了,常用的有分析HTML源碼壹瘟;
- 若提取數(shù)據(jù)完畢鲫剿,就需要把這些數(shù)據(jù)內(nèi)容存儲起來,數(shù)據(jù)內(nèi)容可以保存在文件稻轨、數(shù)據(jù)庫等中灵莲。
實戰(zhàn)
需求:爬取下載整個王者榮耀所有的英雄皮膚
目標(biāo)網(wǎng)址:https://pvp.qq.com/web201605/herolist.shtml
- 查看需要爬取的網(wǎng)頁的編碼
如果讀取的編碼不正確,會出現(xiàn)亂碼的情況殴俱。
右鍵查看源代碼
# 這個utf-8就是網(wǎng)頁的編碼
<meta charset="gbk">
- 請求并設(shè)置讀取網(wǎng)頁編碼格式
# 請求代碼
response = requests.get(url)
# 設(shè)置編碼格式代碼
html_con = response.content.decode('gbk')
3.用etree讀取網(wǎng)頁(需要安裝lxml模塊)
關(guān)于lxml中etree的個人拙見:http://www.reibang.com/p/2802c9d610b5
# 構(gòu)建etree樹
etree = lxml.html.etree
# 用構(gòu)建的etree讀取網(wǎng)頁
parser = etree.HTML(html_con)
4.通過xpath定位目標(biāo)信息
# 匹配class為herolist clearfix的ul下面的li下面的a標(biāo)簽的href的鏈接
wzry_url = input_ele = parser.xpath("http://ul[@class='herolist clearfix']/li/a/@href")
5.請求英雄所在的界面
思路:通過xpath定位獲取到英雄信息的url后政冻,發(fā)現(xiàn)獲取到的url類似于game.gtimg.cn/images/yxzj/img201606/skin/hero-info/528/528-bigskin-1.jpg
這種,所以需要在前面加上域名的前綴线欲,具體方法是用for循環(huán)逐個加完前綴以后再保存到一個數(shù)組內(nèi)明场,代碼如下
from urllib.parse import urljoin
from urllib.parse import urlparse
from posixpath import normpath
from urllib.parse import urlunparse
# 下面方法為拼接url的方法,需要用到上面的幾個包
def myjoin(base, url):
url1 = urljoin(base, url)
arr = urlparse(url1)
path = normpath(arr[2])
return urlunparse((arr.scheme, arr.netloc, path, arr.params, arr.query, arr.fragment))
# 定義一個英雄url數(shù)組
heroArr = []
for i in wzry_url:
# 因為獲取到的url是后綴url 沒有前綴李丰,所以需要補齊前綴myjoin為補齊前綴的方法
heroArr.append(myjoin(wz_url,i))
接下來就是逐個訪問英雄的界面苦锨,保存英雄界面到一個數(shù)組,然后用xpath定位第一個皮膚的鏈接趴泌,因為英雄不只有一個皮膚舟舒,通過觀察發(fā)現(xiàn)多個皮膚的url只是后面的數(shù)字發(fā)生了改變,并且是增序的嗜憔,所以我們可以通過訪問1-15秃励,然后通過返回的狀態(tài)碼來判斷是否有這個皮膚,如果是200則有保存鏈接到圖片數(shù)組中痹筛,404則沒有莺治。這段代碼貼下面,其中還有一些前面講過的就沒講了帚稠,有一定基礎(chǔ)的應(yīng)該看得懂。
# 定義一個圖片鏈接的數(shù)組
pic_pic = []
for i in heroArr:
# 發(fā)送請求
response_1 = requests.get(i)
# 讀取編碼
html_con_1 = response_1.content.decode('gbk')
# 用lxml把網(wǎng)頁變成etree
etree_1 = lxml.html.etree
parser_1 =etree_1 = etree.HTML(html_con_1)
a = parser_1.xpath("http://div[@class='zk-con1 zk-con']/@style")
# 把獲取的url去掉無用的參數(shù)
strA = str(a).replace("[\"background:url(\'//","").replace("\') center 0\"]","")
# 加上http協(xié)議名
strA = ('https://'+strA)
# 獲取所有英雄的所有
isFirst = True
for k in range(1,15):
# 判斷是否是第一張床佳,如果是則直接加入滋早,并且將
if( isFirst ==0):
pic_pic.append(strA)
isFirst = False
# 循環(huán)替換每個鏈接尾部的值
strA = str(strA).replace('-'+str(k),'-'+str(k+1))
# 獲取訪問的狀態(tài)碼
rebianli = requests.get(strA).status_code
# 如果訪問狀態(tài)碼為200 則寫入pic_pic
if(rebianli == 200):
pic_pic.append(strA)
- 下載圖片并保存
訪問每個圖片的鏈接并保存,此處是保存在文件同級目錄的w文件夾中砌们。
# 下載圖片并保存
for pic_pic in pic_pic:
# 訪問圖片的網(wǎng)址杆麸,此處有反爬搁进,加上headers才能獲取圖片。
Aresponse = requests.get(str(pic_pic),headers=headers)
# 訪問保存圖片的二進(jìn)制
Ahtml = Aresponse.content
# 分割
img_split = pic_pic.split('/')
img_name = img_split[len(img_split)-1]
file = open("./w/"+img_name,'wb')
file.write(Ahtml)
file.close()
print("write success")
- 反爬偽裝技術(shù)
有時候發(fā)生請求昔头,目標(biāo)網(wǎng)站可能會識別python發(fā)出的爬蟲饼问,這個時候是爬不到東西的會報錯
例如:http.client.RemoteDisconnected: Remote end closed connection without response
這個時候需要增加一點偽裝技術(shù),根據(jù)目標(biāo)網(wǎng)站的不同揭斧,需要用到的技術(shù)也不同莱革,大概分為以下幾種。
- 在請求頭加入user-agent
這個是有的網(wǎng)站判斷請求的客戶端識別碼讹开,也就是user-agent盅视,應(yīng)對辦法是把請求偽裝成瀏覽器或者移動端。 - 使用代理ip
有的網(wǎng)站會判斷多次請求的ip都是一樣的時候會爬不到東西旦万,應(yīng)對辦法是偽裝成其他的ip闹击。
以下為未優(yōu)化代碼,但是也能用成艘,有時間也不優(yōu)化赏半。因為文件太多,時間太久淆两,可以搞個多線程能解決這個問題除破,看著文檔做應(yīng)該沒問題,有任何問題或者批評在下面留言琼腔。
# -*- coding:utf-8 -*-\
# 導(dǎo)入包
import lxml.html
from urllib.parse import urljoin
from urllib.parse import urlparse
from posixpath import normpath
from urllib.parse import urlunparse
import requests
# 測試代碼
import sys
def myjoin(base, url):
url1 = urljoin(base, url)
arr = urlparse(url1)
path = normpath(arr[2])
return urlunparse((arr.scheme, arr.netloc, path, arr.params, arr.query, arr.fragment))
url ="https://pvp.qq.com/web201605/herolist.shtml"
wz_url = "https://pvp.qq.com/web201605/"
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36'}
# 發(fā)送請求
response = requests.get(url)
# 讀取編碼
html_con = response.content.decode('gbk')
# sys.exit()
# 構(gòu)建etree樹
etree = lxml.html.etree
# 用構(gòu)建的etree讀取網(wǎng)頁
parser = etree.HTML(html_con)
# //表示不考慮元素位置 只要在代碼都匹配到
# //h1/a/text() 表示h1下面的a標(biāo)簽的文本
# a_text = input_ele = parser.xpath("http://h1/a/text()")
# 匹配h1下面的a標(biāo)簽的url
# a_url = input_ele = parser.xpath("http://h1/a/@href")
wzry_url = input_ele = parser.xpath("http://ul[@class='herolist clearfix']/li/a/@href")
# sys.exit()
heroArr = []
for i in wzry_url:
# 因為獲取到的url是后綴url 沒有前綴瑰枫,所以需要補齊前綴myjoin為補齊前綴的方法
heroArr.append(myjoin(wz_url,i))
# 定義一個圖片鏈接的數(shù)組
pic_pic = []
for i in heroArr:
# 發(fā)送請求
response_1 = requests.get(i)
# 讀取編碼
html_con_1 = response_1.content.decode('gbk')
# 用lxml把網(wǎng)頁變成etree
etree_1 = lxml.html.etree
parser_1 =etree_1 = etree.HTML(html_con_1)
a = parser_1.xpath("http://div[@class='zk-con1 zk-con']/@style")
# 把獲取的url去掉無用的參數(shù)
strA = str(a).replace("[\"background:url(\'//","").replace("\') center 0\"]","")
# 加上http協(xié)議名
strA = ('https://'+strA)
# 獲取所有英雄的所有
isFirst = True
for k in range(1,15):
# 判斷是否是第一張,如果是則直接加入丹莲,并且將
if( isFirst ==0):
pic_pic.append(strA)
isFirst = False
# 循環(huán)替換每個鏈接尾部的值
strA = str(strA).replace('-'+str(k),'-'+str(k+1))
# 獲取訪問的狀態(tài)碼
rebianli = requests.get(strA).status_code
# 如果訪問狀態(tài)碼為200 則寫入pic_pic
if(rebianli == 200):
pic_pic.append(strA)
# 下載圖片并保存
for pic_pic in pic_pic:
# 訪問圖片的網(wǎng)址
Aresponse = requests.get(str(pic_pic),headers=headers)
# 訪問保存圖片的二進(jìn)制
Ahtml = Aresponse.content
# 分割
img_split = pic_pic.split('/')
img_name = img_split[len(img_split)-1]
file = open("./w/"+img_name,'wb')
file.write(Ahtml)
file.close()
print("write success")