目標(biāo):
爬取某8的一頁(yè)商品信息,介于老師給的網(wǎng)址全是轉(zhuǎn)轉(zhuǎn)信息因此我自己選擇了一個(gè)賣狗的頁(yè)面(捂臉)
界面如下:(排除了心寵的所有推廣)
我們需要爬取商家和個(gè)人兩個(gè)部分的詳情頁(yè)信息
爬取結(jié)果:
難點(diǎn)
- 瀏覽人數(shù)的爬取
- 爬取的網(wǎng)址跟跳轉(zhuǎn)的網(wǎng)址不同
- 不同網(wǎng)頁(yè)完善的信息不同(比如有的有電話有的沒(méi)有)
- 個(gè)人和商家版的詳情頁(yè)元素位置有輕微區(qū)別(比如同一個(gè)位置會(huì)存放不同內(nèi)容信息)
- 爬取的文本有大量/t/r/n的信息
- 挑戰(zhàn)自己爬了下需要點(diǎn)擊才能顯示的電話號(hào)碼
代碼
from bs4 import BeautifulSoup
import time
import requests
def get_urls(path,name_num):
respond = requests.get(path)
soup = BeautifulSoup(respond.text, 'lxml')
pre_urls = soup.select('''td.t > a[onclick="clickLog('from=pc_cwgou_list_wenzi');"]''')
i = 0
urls = []
file = open('./urls{}.txt'.format(name_num),'a')
for url in pre_urls:
i = i + 1
href = url.get('href')
urls.append(href)
text = url.get_text()
print(i,' ',href,text)
file.write(str(i)+' '+ href +'\n'+text+'\n\n')
file.close()
return urls
def get_views(url):
time.sleep(2)
get_num1 = url.split('x.shtml')
get_num2 = get_num1[0].split('dog/')[-1]
api = 'http://jst1.58.com/counter?infoid={}'.format(get_num2)
headers = {
'Referer':'http://m.58.com/tj/dog/{}'.format(get_num2),
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1'
}
js = requests.get(api,headers = headers)
views = js.text.split('total=')[-1]
return views
def detail (path, count, Hkind_judge) :
respond = requests.get(path)
views = get_views(respond.url)
soup = BeautifulSoup(respond.text,'lxml')
url_kind = soup.select('#header > div.breadCrumb.f12 > span:nth-of-type(4) > a')
kind = soup.select('body > div.content_quanbu > div.zhanshi_top.clearfix > div.zhanshi_top_l.fl.clearfix > div.col_sub.sumary.fl > ul > li:nth-of-type({}) > div.su_con > span:nth-of-type(1)'.format(3 if Hkind_judge == 0 else 4))
title = soup.select('body > div.content_quanbu > div.col_sub.mainTitle > div > h1')
date = soup.select('#index_show > ul.mtit_con_left.fl.clearfix > li.time.fl > span')
num = soup.select('span.zhishu')
pos = soup.select('span.dizhi')
host = soup.select('span.lianxiren > a')
phone = soup.select('#t_phone')
if Hkind_judge == 0:
host_kind = '個(gè)人'
elif Hkind_judge == 1:
host_kind = '商家'
else:
host_kind = '未知'
list = [
'網(wǎng)頁(yè)分類:'+ url_kind[0].get_text() if url_kind else '網(wǎng)頁(yè)分類:None',
'網(wǎng)頁(yè)標(biāo)題:'+ title[0].get_text() if title else '網(wǎng)頁(yè)標(biāo)題:None',
'發(fā)帖日期:'+ date[0].get_text() if date else '發(fā)帖日期:None',
'店家類型:'+ host_kind,
'瀏覽次數(shù):'+ views,
'寵物種類:'+ kind[0].get_text().replace('\t', '').replace('\n','').replace(' ','') if kind else '寵物種類:None',
'主人:'+ host[0].get_text() if host else '主人:None',
'電話:'+ phone[1].get_text() if len(phone) > 1 else '電話:None',
'只數(shù):'+ num[0].get_text() if num else '只數(shù):None',
'位置:'+ pos[0].get_text() if pos else '位置:None'
]
print(list)
file_path = './imformation.txt'
file = open(file_path, 'a')
file.write('第'+str(count)+'個(gè)\n')
for i in list:
file.write(i+'\n')
file.write('\n\n')
file.close()
path1 = 'http://bj.58.com/dog/1/?PGTID=0d3000fc-0000-13b1-ca3b-4d326020e12d&ClickID=1'
path0 = 'http://bj.58.com/dog/0/?PGTID=0d3000fc-0000-13b1-ca3b-4d326020e12d&ClickID=1'
urls0 = get_urls(path0,'0')
count = 0
for url0 in urls0:
time.sleep(2)
count = count + 1
detail(url0,count,Hkind_judge = 0)
urls1 = get_urls(path1,'1')
count = 0
for url1 in urls1:
time.sleep(2)
count = count + 1
detail(url1, count,Hkind_judge = 1)
其實(shí)個(gè)人和商家兩個(gè)部分的網(wǎng)址也是可以用format來(lái)做到的,我這里一開(kāi)始貪圖簡(jiǎn)單沒(méi)有用循環(huán)遭笋,但是后期發(fā)現(xiàn)很多地方要用到0、1兩個(gè)變量(包括兩份網(wǎng)址txt的命名和商品詳情里出處的判斷)
總結(jié):
說(shuō)一下上面難點(diǎn)的解決方案
-
瀏覽人數(shù):
先打開(kāi)檢查是偷,sources星压,刷個(gè)新晒喷,可以找到一個(gè)js文件愚争,把這個(gè)地址復(fù)制下來(lái)映皆,進(jìn)行g(shù)et請(qǐng)求就可以獲得這個(gè)js瀏覽量的返回(即數(shù)據(jù)部分最后的total = xxxx)
這個(gè)文件的Infoid一串?dāng)?shù)字和網(wǎng)址的id是一致的挤聘,因此把網(wǎng)址的id取出來(lái)轰枝,就可以用fomat批量獲取js啦
但是我還遇到一個(gè)問(wèn)題,就是照做了之后還是爬不到组去,返回total=0鞍陨,這個(gè)時(shí)候加個(gè)Header的Referer試試就可以
def get_views(url):
time.sleep(2)
get_num1 = url.split('x.shtml')
get_num2 = get_num1[0].split('dog/')[-1]
api = 'http://jst1.58.com/counter?infoid={}'.format(get_num2)
headers = {
'Referer':'http://m.58.com/tj/dog/{}'.format(get_num2),
'User-Agent': 'Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1'
}
js = requests.get(api,headers = headers)
views = js.text.split('total=')[-1]
return views
- 那么問(wèn)題來(lái)了,要得到網(wǎng)址中的id从隆,但是看我的結(jié)果txt诚撵,發(fā)現(xiàn)爬取的第一個(gè)網(wǎng)頁(yè)是和下面不一樣,沒(méi)有一串?dāng)?shù)字的键闺,這是因?yàn)檫@是跳轉(zhuǎn)前的網(wǎng)址寿烟,我們無(wú)法判斷得到的網(wǎng)址是否還有一次跳轉(zhuǎn),所以解決方法是取瀏覽量之前辛燥,取已打開(kāi)詳情頁(yè)的網(wǎng)址進(jìn)行分析(已跳轉(zhuǎn)完成的)
respond = requests.get(path)
views = get_views(respond.url)
- 不同網(wǎng)頁(yè)完善的信息不同筛武,所以一旦沒(méi)有獲取到需要的內(nèi)容,程序會(huì)死掉哦~怎么解決這個(gè)問(wèn)題呢挎塌,就因?yàn)檫@個(gè)調(diào)試到了今天(所以遲交了作業(yè)徘六,抱歉)
解決方法是要養(yǎng)成每個(gè)信息都要判斷是否存在的習(xí)慣
突然聯(lián)系到直播的時(shí)候老師有個(gè)這樣的習(xí)慣,在每個(gè)獲取信息輸出之前榴都,會(huì)
判斷列表是否為空待锈,像這樣:if list else None
list = [
'網(wǎng)頁(yè)分類:'+ url_kind[0].get_text() if url_kind else '網(wǎng)頁(yè)分類:None',
'網(wǎng)頁(yè)標(biāo)題:'+ title[0].get_text() if title else '網(wǎng)頁(yè)標(biāo)題:None',
'發(fā)帖日期:'+ date[0].get_text() if date else '發(fā)帖日期:None',
'店家類型:'+ host_kind,
'瀏覽次數(shù):'+ views,
'寵物種類:'+ kind[0].get_text().replace('\t', '').replace('\n','').replace(' ','') if kind else '寵物種類:None',
'主人:'+ host[0].get_text() if host else '主人:None',
'電話:'+ phone[1].get_text() if len(phone) > 1 else '電話:None',
'只數(shù):'+ num[0].get_text() if num else '只數(shù):None',
'位置:'+ pos[0].get_text() if pos else '位置:None'
]
我用List存放是為了輸出的txt格式好看一點(diǎn),如果要輸出其他的要用字典什么的啦
可以看到個(gè)人信息頁(yè)面很多東西都是None因?yàn)樗麄儧](méi)有寫(xiě)
- 個(gè)人和商家版的詳情頁(yè)元素位置有輕微區(qū)別嘴高,這個(gè)導(dǎo)致我爬品種的時(shí)候竿音,總是會(huì)一部份顯示防疫的內(nèi)容,一部分顯示品種
解決辦法是判斷當(dāng)前是商家版還是個(gè)人版拴驮,改變位置春瞬,我這里用format(Hkind_judge是主人類型判斷...名字奇怪了點(diǎn)哈)
kind = soup.select('body > div.content_quanbu > div.zhanshi_top.clearfix > div.zhanshi_top_l.fl.clearfix > div.col_sub.sumary.fl > ul > li:nth-of-type({}) > div.su_con > span:nth-of-type(1)'.format(3 if Hkind_judge == 0 else 4))
- 爬取的文本有大量/t/r/n的信息,要怎么刪除呢莹汤?(說(shuō)的就是品種信息)
刪除的方法其實(shí)有很多種快鱼,我這里用了最粗暴的repla
'寵物種類:'+ kind[0].get_text().replace('\t', '').replace('\n','').replace(' ','') if kind else '寵物種類:None'
- 挑戰(zhàn)自己爬了下需要點(diǎn)擊才能顯示的電話號(hào)碼
然后我發(fā)現(xiàn)并不難,因?yàn)檫@個(gè)沒(méi)有用js控制,直接就放在網(wǎng)頁(yè)源碼抹竹,所以只要判斷好它的位置就可以线罕,要小心的是所有select結(jié)果都是列表,沒(méi)把握需要的信息在哪里的窃判,就先print出來(lái)
這里遇到的問(wèn)題其實(shí)就是有的詳情沒(méi)有給電話钞楼,但是得到的列表依然是有一個(gè)值的,所以這里不是判斷為空袄琳,而是判斷元素個(gè)數(shù)是否大于1
'電話:'+ phone[1].get_text() if len(phone) > 1 else '電話:None'
- 變量名比較混亂抱歉询件,因?yàn)闀?huì)的單詞實(shí)在不夠多(捂臉),然后也忘了爬價(jià)格唆樊,不過(guò)我覺(jué)得價(jià)格應(yīng)該也不難宛琅,所以就不管了
這一次大作業(yè)確實(shí)發(fā)現(xiàn)了很多之前的網(wǎng)頁(yè)不存在的問(wèn)題,做起來(lái)比較辛苦逗旁,但是好有成就感~
順便為了保護(hù)嘿辟,每個(gè)請(qǐng)求都加了time.sleep(2)保護(hù),但是這個(gè)方法速度實(shí)在是慢了點(diǎn) - 嘛這周的作業(yè)也要加油了(づ ̄ 3 ̄)づ