呜呜~~本来说今天就把代码上传上来,可惜了,还是有点差错,今天估计赶不上啦!明天加油吧!
今天我们一起来好好分析一下,看看我们该如何去爬去58二手商品。
这里我们分成四步来完成本次任务~
目标站点分析
目标URL:http://bj.58.com/sale.shtml
第一步:主页分析
在主页里面,我们需要提取说有的二级分类,特别注意,绿色框的内容,它的格式和内容,如其他的内容相差较大,所以我们一开始就把它剔除,从而在一定程度上减轻代码量和工作内容。
# 解析main_url = "http://bj.58.com/sale.shtml" 获取分类URL
def parse_index(self):
category_urls = []
html = self.parse_url(self.main_url)
soup = BeautifulSoup(html.text, 'lxml')
links = soup.select("ul.ym-submnu > li > b > a")
for link in links:
link_url = urljoin(self.main_url, link.attrs['href'])
category_urls.append(link_url)
self.DB.insert(collection='Category_urls', item=category_urls)
第二步:提取详情页链接
观察列表页,我们发现,有一些的详情页中不存在‘价格’,所以我们可以在提取详情页链接的时候直接将其筛选出来,这样我们在数据分析的时候就可以少做一点事了。
# 解析分类链接并提取获取商品详情URL
def parse_page_url(self):
items = self.DB.find_data(collection='Category_urls')
for item in items:
cate_urls = item['category_urls']
for cate_url in cate_urls:
page_urls = []
self.proxy = self.get_proxy()
if 'tongxunyw' in cate_url:
print("error", cate_url)
pass
elif 'ershouqiugou' in cate_url:
print("error", cate_url)
pass
else:
print(cate_url)
for i in range(1, 100):
print("Parse page ", i)
url = cate_url + 'pn{}/'.format(i)
html = self.parse_url(url)
soup = BeautifulSoup(html.text, 'lxml')
trs = soup.select("tr[_pos='0']")
for tr in trs:
price = tr.select("b.pri")[0].get_text()
if price != '面议':
temp_link = tr.select("td.t > a:nth-of-type(1)")[0].attrs['href']
page_url = urljoin(self.main_url, temp_link)
page_urls.append(page_url)
item = dict(
page_urls=page_urls,
)
self.DB.insert(collection='Page_urls', items=item)
第三步:提取详情页数据
由于该详情页大致分为三种,所以必须采用三种模式去提取数据,如图
一眼看上去都差不多,但实际上里面的内容却有着很大的差别,比如说来之转转的内容,你不能直接冲网页里提取,而是的痛过转转API,获取json数据,在提取!笔者在编码时,也是调试了很多次才发现,原来这里有三种页面。醉了!没有办法,只好硬着头皮,写下去~
# 解析Old58_urls网页,pp
def parse_page_58(self, page_url):
html = self.parse_url(page_url)
soup = BeautifulSoup(html.text, 'lxml')
temp_title = soup.title.get_text()
title = temp_title.split(" - ")[0]
try:
temp_time = soup.select("div.detail-title__info > div")[0].get_text()
time = temp_time.split(" ")[0]
temp_price = soup.select("span.infocard__container__item__main__text--price")[0].get_text()
price = temp_price.split()[0]
temp = soup.select("div.infocard__container > div:nth-of-type(2) > div:nth-of-type(2)")[0].get_text()
if '成新' in temp:
color = temp
temp_area = soup.select("div.infocard__container > div:nth-of-type(3) > div:nth-of-type(2)")[0]
else:
color = None
temp_area = soup.select("div.infocard__container > div:nth-of-type(2) > div:nth-of-type(2)")[0]
temp_area = list(temp_area.stripped_strings)
area = list(filter(lambda x: x.replace("-", ''), temp_area))
temp_cate = list(soup.select("div.nav")[0].stripped_strings)
cate = list(filter(lambda x: x.replace(">", ''), temp_cate))
item = dict(
title=title,
time=time,
price=price,
color=color,
area=area,
cate=cate,
)
print(item)
self.DB.insert(collection='Page_data', items=item)
except:
print("Error 404!")
# 解析New58_urls网页,并提取数据
def parse_page_now58(self, page_url):
html = self.parse_url(page_url)
soup = BeautifulSoup(html.text, 'lxml')
try:
title = soup.select("div.detail-info-tit")[0].get_text()
temp_cate = soup.select("div.nav")[0]
temp_cate = list(temp_cate.stripped_strings)
cate = list(filter(lambda x: x.replace(">", ''), temp_cate))
ul = soup.select("ul.detail-info-bd")[0]
time = ul.select("li:nth-of-type(1) > span:nth-of-type(2)")[0].get_text()
color = ul.select("li:nth-of-type(2) > span:nth-of-type(2)")[0].get_text()
area = ul.select("li:nth-of-type(3) > span:nth-of-type(2)")[0].get_text()
temp_price = soup.select("span.info-price-money")[0].get_text()
price = temp_price.split("¥")[-1]
item = dict(
title=title,
time=time,
price=price,
color=color,
area=area,
cate=cate,
)
print(item)
self.DB.insert(collection='Page_data', items=item)
except:
print("Error 404!")
# 解析来自ZZ58_urls网页,并提取json数据
def parse_page_zz(self, page_url):
pattern = re.compile('infoId=(.*?)&', re.S)
infoId = re.findall(pattern, page_url)
html = self.parse_url(self.temp_api.format(infoId[0]))
try:
data_json = html.json()
data = data_json.get('respData')
local = data.get("location")
item = dict(
title=data.get('title'),
browse_times=data.get("browseCount"),
price=data.get("nowPrice"),
origin_price=data.get("oriPrice"),
area=local.get("local"),
)
print(item)
self.DB.insert(collection='Page_data', items=item)
except:
print("Error 404!")
第四步:爬虫逻辑
由于整个的爬去量有点大,内容也相当的多,所以,我把数据都存储到了MongoDB里面,方便后续的使用,在爬虫时,也采用多进程分步的方式去爬去内容。减轻服务器的承担量~
# 逻辑实现
def run(self):
if INDEX_ENABLED:
Index_process = Process(target=self.parse_index)
Index_process.start()
if LINK_ENABLED:
PageUrl_process = Process(target=self.parse_page_url)
PageUrl_process.start()
if ITEM_ENABLED:
Page_process = Process(target=self.parse_page)
Page_process.start()
好了,今天的爬虫,就先讲到这里啦,代码里还有一些问题,明天调试好了,上传上来~
源码地址:https://github.com/NO1117/Sale58_Spider
Python交流群:942913325 欢迎大家一起交流学习
Question:如何进一步提高爬虫效率?大家可以考虑一下多线程多进程的方式~实现的可以找我聊聊哈