需求
- 爬取若干頁上的商品
- 不包含推廣商品和轉(zhuǎn)轉(zhuǎn)商品
- 獲取相應(yīng)商品的詳細信息掸读,例如:標題、發(fā)布時間、成色儿惫、價格澡罚、區(qū)域、瀏覽量等
開發(fā)環(huán)境
Win7 64bit肾请、Python3.5
代碼
# -*- coding: utf-8 -*-
from bs4 import BeautifulSoup
import requests
import time
agent = 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36'
cookie = 'f=n; f=n; id58=c5/ns1dl9yy83HPfDdvGAg==; ipcity=zz%7C%u90D1%u5DDE%7C0; als=0; __utma=253535702.38279276.1466300209.1466300209.1466300209.1; __utmc=253535702; __utmz=253535702.1466300209.1.1.utmcsr=zz.58.com|utmccn=(referral)|utmcmd=referral|utmcct=/; bj=201661993651; bj58_id58s="WEVVdFlpeD1VM3hkNjQ3MQ=="; sessionid=e2fa9381-317b-4e3f-9e1c-fd3705f6c894; myfeet_tooltip=end; 58home=bj; __track_id=20160619093746385471429630431203178; Hm_lvt_4d4cdf6bc3c5cb0d6306c928369fe42f=1466300268; Hm_lpvt_4d4cdf6bc3c5cb0d6306c928369fe42f=1466300268; city=bj; bdshare_firstime=1466300280136; bangbigtip2=1; f=n; final_history=26224745105338%2C25245379987755%2C26394563690054%2C26399654836521%2C26010296256313; bj58_new_session=0; bj58_init_refer=""; bj58_new_uv=3; 58tj_uuid=1b067d6e-d9f3-4b82-818b-3cdd2263501c; new_session=0; new_uv=3; utm_source=; spm=; init_refer='
referer = 'http://bj.58.com/pbdnipad/0/?PGTID=0d3065d1-0000-114f-c494-6fa3a1961632&ClickID=1'
headers = {'User-Agent':agent,'Cookie':cookie,'Referer':referer}
# 獲取頁面上除了推廣和轉(zhuǎn)轉(zhuǎn)外始苇,所有商品的鏈接,將鏈接存儲在list中返回筐喳。函數(shù)有兩個參數(shù)催式,end_page參數(shù),
# 表示要獲取商品的頁數(shù)避归,sale參數(shù)默認為0荣月,表示要獲取個人商品,若要獲取商家商品時梳毙,將sale置為1哺窄。
def get_links_from_page(end_page,sale=0):
links= []
for page in range(1,end_page+1):
url = 'http://bj.58.com/pbdn/{}/pn{}/'.format(sale,page)
r = requests.get(url, headers=headers)
if r.status_code != 200:
continue
time.sleep(4)
soup = BeautifulSoup(r.text, 'lxml')
for tr in soup.select('#infolist > table.tbimg'): #避開了推廣商品
for item in tr.find_all('tr', class_=''): #避開了轉(zhuǎn)轉(zhuǎn)商品,注意class_的寫法
links.append(item.select('td.t > a.t')[0].get('href'))
# print(links)
return links
# 獲取某一個商品的瀏覽量,瀏覽量是js控制的账锹,直接抓取標簽會返回0萌业,在headers中藥加入referer
def get_views(url):
id = url.split('?')[0].split('/')[-1].strip('x.shtml')
infoid = 'http://jst1.58.com/counter?infoid={}'.format(id)
r = requests.get(infoid,headers=headers)
views = r.text.split('=')[-1]
return views
# 獲取商品的信息
def get_info(end_page,sale=0):
urls = get_links_from_page(end_page,sale=0)
for url in urls:
r = requests.get(url, headers = headers)
if r.status_code != 200:
continue
time.sleep(2)
soup = BeautifulSoup(r.text, 'lxml')
cate = soup.select('span > a[)
title = soup.select('div > h1')
date = soup.select('li.time')
price = soup.select('span.price')
state = soup.find_all('div', 'su_con')
region = soup.select('.c_25d')
data = {
'category':cate[0].get_text(),
'title':title[0].get_text(),
'date':date[0].get_text(),
'price':price[0].get_text(),
'state':list(state[1].stripped_strings)[0],
'region':''.join(list(region[0].stripped_strings)) if len(region)!=0 else '-',
'seller':'個人' if sale == 0 else '商家',
'views': get_views(r.url), #重定向鏈接
}
print(data)
# 爬取前兩頁的信息
get_info(2)
運行結(jié)果
遇到的問題和解決方案
獲取瀏覽量時,Chrome一直顯示瀏覽量為0奸柬,即使刷新后也沒有變化生年,在Sources中也沒有發(fā)現(xiàn)任何URL返回瀏覽量信息。折騰了一個晚上廓奕,發(fā)現(xiàn)是chrome中的adblock plus沒關(guān)抱婉,關(guān)掉后一切正常了。
使用get_view()函數(shù)獲取瀏覽量桌粉,最初只把相應(yīng)的網(wǎng)站傳入蒸绩,結(jié)果發(fā)有一個商品的瀏覽量是0,后來發(fā)現(xiàn)該鏈接有重定向鏈接铃肯,使用
r.url
獲取重定向后的鏈接即可患亿。選取網(wǎng)頁元素時,使用CSS Selector復制路徑即可押逼,但是復制的路徑不一定能用步藕,如果出現(xiàn)nth-child(),要改為nth-of-type()宴胧。路徑中的'>'兩邊要有空格漱抓,否則會報錯。
<tbody>標簽導致無法正常選取標簽
在最初編程時恕齐,為了避免選中推廣商品的標簽,曾將路徑設(shè)為#infolist > table.tbimg > tbody > tr > td.t > a.t
(這樣依然會選中轉(zhuǎn)轉(zhuǎn)商品),結(jié)果竟然返回[]
显歧。代碼如下:
# -*- coding: utf-8 -*-
from bs4 import BeautifulSoup
import requests
url = 'http://bj.58.com/pbdn/0/'
r = requests.get(url)
soup = BeautifulSoup(r.text, 'lxml')
tag = soup.select(#infolist > table.tbimg > tbody > tr > td.t > a.t)
print(tag)
#結(jié)果為[]
原因和解決方案:
雖然在Elements下存在tbody標簽仪或,但是網(wǎng)頁源代碼中并沒有該標簽,如果使用print(soup)
士骤,發(fā)現(xiàn)結(jié)果中也沒有tbody標簽范删。在網(wǎng)頁中,tbody位于table中拷肌,用來提高解析速度到旦。將路徑改為#infolist > table.tbimg > tr > td.t > a.t
即可。
總結(jié)
- 瀏覽量是JS控制的巨缘,不能通過選取標簽的方式獲取
- 標簽的選取需要逐步嘗試
- 為了避開網(wǎng)站的反爬機制添忘,需要添加headers,設(shè)置爬取的時間間隔
- 路徑的含義
例如:#infolist > table.tbimg > tbody > tr a.t
路徑若锁,table.tbimg指class=tbimg的table標簽搁骑,#infolist指id=infolist的標簽,> 代表直接子標簽又固,tr a.t
之間的空格代表a是tr的間接子標簽仲器。