java爬去赶集,动手写爬虫(3):爬取赶集网二手物品信息

掌握了BeatifulSoup的基本用法之后,爬取单个网页实际上是比较简单的:只需要使用requests库中的get方法先向网页发出请求,用BeatifulSoup把网页转成soup,再对soup使用各种select方法,即可得到所需的网页元素,再稍做整理,即可得到所需的结构化内容。

那么,如果要爬取一系列的网页内容呢?

这就需要对爬取过程做一下调度准备了,下面以赶集网二手物品信息为例,介绍一下10万量级网页的爬取过程。

0.爬取目标

选择一个地市的赶集全部二手物品类目作为爬取目标,爬取其下所有二手物品页面、二手物品详细信息。

b43f312a605c

赶集二手物品类目.png

b43f312a605c

爬取目标.png

1.制定爬取过程策略

我们按照倒序来分析一下爬取过程

-最后一步:爬取最终的爬取页面,也就是上面的图二(爬取目标),存储所需信息

-倒数第二步:通过类目页面获取最后一步所需的最终页面的链接

-倒数第三步:想办法获取类目页面链接

我们再把这个过程正过来,也就是正常在赶集上找到对应物品信息的过程——爬取过程就是把这个找寻的过程重复再重复。

当然,上述处理过程中,需要将中间爬取的链接一步一步存储下来、一步一步再提取出来使用,并规避重复。

b43f312a605c

**大规模爬取信息过程**.png

2.动手开始爬!

过程明确了,实现起来就不复杂了。主要需要注意的是中间存url、取url的过程:注意避免重复——爬过的留一个已爬记录,爬前到这个记录里检查一下有没有,如果已爬,那就跳过!

(1)第一部分代码:获取类目信息

import requests

from bs4 import BeautifulSoup

headers = {

'user-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.94 Safari/537.36'

}

home_url = 'http://xa.ganji.com/wu/'

wb_data = requests.get(home_url,headers = headers)

soup = BeautifulSoup(wb_data.text,'lxml')

#print(soup)

utag = soup.select('dl > dt > a[target="_blank"]')

url_list = ''

for item in utag:

utag_tag = item.get('href')

#print(utag_tag)

url = 'http://xa.ganji.com{}'.format(utag_tag)

url_list = url_list + url + '\n'

print(url)

获取完后,把类目url存储为变量channel_list,备用。

(2)第二部分代码:两个获取页面信息的函数

这一步我们先写获取最终页面链接的函数、再写通过最终链接获取目标信息对应的函数。

函数1的参数有类目链接、子页面编码两个,在调用这个函数的时候,我们再去写对应的编码循环、类目循环。

函数2的参数只有最终页面链接一个。

import pymongo

import requests

from bs4 import BeautifulSoup

import time

from get_ori_url import channel_list,headers

client = pymongo.MongoClient('localhost',27017)

ganji = client['ganji']

#重新建立一个url集

urlset = ganji['urlset']

urlspideset = ganji['urlspideset']

second_info = ganji['second_info']

#step1: get the urls of secondhand

def get_urls(channel,pages):

url_secondhands = '{}o{}'.format(channel,pages)

time.sleep(6)

print(url_secondhands)

db_urls = [item['url'] for item in channel_sec.find()]

if url_secondhands in db_urls:

print('the',url_secondhands,'has spide already!')

pass

else:

wb_data = requests.get(url_secondhands,headers = headers)

soup = BeautifulSoup(wb_data.text,'lxml')

#add the url into have spide

channel_sec.insert_one({'url':url_secondhands})

#add: if page error,then pass

url_secondhand = soup.select('dd.feature > div > ul > li > a')

for item in url_secondhand:

url_s = item.get('href')

urlset.insert_one({'url':url_s})

print(url_s)

# insert the url had spide into a set;

#step2: get the information we need from the secondhand pages

def get_item_info(url):

time.sleep(2)

db_urls = [item['url'] for item in urlspideset.find()]

if url in db_urls:

print('the url "',url,'"has aready spide!')

pass

else:

wb_data = requests.get(url,headers=headers)

soup = BeautifulSoup(wb_data.text,'lxml')

title = soup.select('h1')

pagetime = soup.select('div.col-cont.title-box > div > ul.title-info-l.clearfix > li:nth-of-type(1) > i')

type = soup.select('div.leftBox > div:nth-of-type(3) > div > ul > li:nth-of-type(1) > span > a')

price = soup.select('div > ul > li:nth-of-type(2) > i.f22.fc-orange.f-type')

address = soup.select('div.leftBox > div:nth-of-type(3) > div > ul > li:nth-of-type(3)')

# can't get the pv,need other method

# pageview = soup.select('pageviews')

for t1,p1,type1,price1,add1 in zip(title,pagetime,type,price,address):

data = {

'title':t1.get_text(),

'pagetime':(p1.get_text().replace('发布','')).strip(),

'type':type1.get_text(),

'price':price1.get_text(),

'address':list(add1.stripped_strings)

}

second_info.insert_one(data)

print(data)

urlspideset.insert_one({'url':url})

(3)第三部分代码:调用上述函数获取目标信息

首先是调用函数get_urls,通过类目信息,获取最终页面链接集:

from multiprocessing import Pool

from get_ori_url import channel_list

from spider_ganji import get_urls

def get_url_from_channel(channel):

for num in range(1,71):

get_urls(channel,num)

if __name__ == '__main__':

pool = Pool()

pool.map(get_url_from_channel,channel_list.split())

根据调用的函数,获取的链接会存储在MongoDB下的ganji库urlset表中。

再调用函数 get_item_info,逐个页面获取所需信息:

from multiprocessing import Pool

from spider_ganji import get_item_info

from spider_ganji import urlset

from spider_ganji import urlspideset

#get all urls need to spide:

db_urls = [item['url'] for item in urlset.find()]

#get the urls already spide:

url_has_spide = [item['url'] for item in urlspideset.find()]

x = set(db_urls)

y = set(url_has_spide)

rest_urls = x-y

if __name__ == '__main__':

pool = Pool()

pool.map(get_item_info,rest_urls)

这一步用了一点去除已爬页面的技巧:首先是爬的过程中将已爬取url记录下来(也可以存储在所爬信息库中),如果出现中断,用所有需爬取 剔除 已爬取,即可规避重复爬取问题。

(关于剔重、规避中断过程中出现的问题,应该还有更好的解决方案:先记录异常页面、跳过、继续爬,最后再处理异常页面应该更合适?)

3.总结

大道至简,问题的解决方案应该是简洁的,大规模的数据爬取也是一样:难点并不在于某几个页面怎么爬,而在于过程上的控制和调度:调度过程越清晰,实现起来越容易,实现过程中多翻翻文档就好了(虽然我也觉得文档看起来累,不过确实还得翻,就跟认字时翻字典一样——现在只需要翻“电子词典”已经很方便了!)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
【为什么学爬虫?】        1、爬虫入手容易,但是深入较难,如何出高效率的爬虫,如何出灵活性高可扩展的爬虫都是一项技术活。另外在爬虫过程中,经常容易遇到被反爬虫,比如字体反、IP识别、验证码等,如何层层攻克难点拿到想要的数据,这门课程,你都能学到!        2、如果是作为一个其他行业的开发者,比如app开发,web开发,学习爬虫能让你加强对技术的认知,能够开发出更加安全的软件和站 【课程设计】 一个完整的爬虫程序,无论大小,总体来说可以分成三个步骤,分别是:络请求:模拟浏览器的行为从上抓数据。数据解析:将请求下来的数据进行过滤,提我们想要的数据。数据存储:将提到的数据存储到硬盘或者内存中。比如用mysql数据库或者redis等。那么本课程也是按照这几个步骤循序渐进的进行讲解,带领学生完整的掌握每个步骤的技术。另外,因为爬虫的多样性,在的过程中可能会发生被反、效率低下等。因此我们又增加了两个章节用来提高爬虫程序的灵活性,分别是:爬虫进阶:包括IP代理,多线程爬虫,图形验证码识别、JS加密解密、动态爬虫、字体反识别等。Scrapy和分布式爬虫:Scrapy框架、Scrapy-redis组件、分布式爬虫等。通过爬虫进阶的知识点我们能应付大量的反站,而Scrapy框架作为一个专业的爬虫框架,使用他可以快速提高我们编爬虫程序的效率和速度。另外如果一台机器不能满足你的需求,我们可以用分布式爬虫让多台机器帮助你快速数据。 从基础爬虫到商业化应用爬虫,本套课程满足您的所有需求!【课程服务】 专属付费社群+定期答疑

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值