成果:

代碼在github:
趕集爬蟲
整體思路:
1.爬取page_url。

這個基本都是套路,很容易爬取,然后存在page_url這個數(shù)據(jù)庫中
2.爬取index檢索頁

從page_url拿出來打開的頁面,進(jìn)入到page_url,把每個預(yù)覽頁面的url給剝離出來存到preview_url這個數(shù)據(jù)庫。必須加上驗證是否是有效頁面。因為你不知道有多少頁,所以就找一下數(shù)字比較大的頁面看看區(qū)別是什么樣的。
我在這里是用了大的頁面沒有page_box這個類,而終止爬取
3.爬取詳情頁面

所有的頁面結(jié)構(gòu)是一樣的也就是說,他們做網(wǎng)站的輕松,所以搞得我們爬取也輕松,就是這個道理。也就是說,無論電腦還是飾品分類都是一樣的頁面布局。
這步實現(xiàn)是從preview_url數(shù)據(jù)庫拿出來數(shù)據(jù)來爬取詳細(xì)信息然后存儲到info_details。每個條目加上url,方便以后去重
4.整體思路就是以上,還有一些新手段:
- 去重就是在數(shù)據(jù)庫檢索有沒有這個數(shù)據(jù)一般我們提取數(shù)據(jù)庫的數(shù)據(jù)是[i['url'] for i in first_grade.find()],這樣就返回了一個列表,你在用 url in [a,b,c……]這個布爾值來判斷是否需要插入信息
新技能GET:
1.進(jìn)程池,
import multiprocessing
def do_calculation(data):
return data * 2
def start_process():
print('Starting', multiprocessing.current_process().name)
if __name__ == '__main__':
inputs = list(range(10))
print('Inputs :', inputs)
# 這個是不用進(jìn)程池,Python原生的方法
builtin_output = map(do_calculation, inputs)
print('Build-In :', [i for i in builtin_output])
# 用到進(jìn)程池的方法
# 整個cpu_count()可以計算cpu內(nèi)核數(shù),不用裝魯大師去查了
# 開了4個進(jìn)程池
pool_size = multiprocessing.cpu_count() * 2
print('pool_size:', pool_size)
pool = multiprocessing.Pool(processes=pool_size,
initializer=start_process, )
pool_outputs = pool.map(do_calculation, inputs)
pool.close()
pool.join()
print('Pool outputs:', pool_outputs)
輸出是:
Inputs : [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Build-In : [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
pool_size: 4
Starting SpawnPoolWorker-1
Starting SpawnPoolWorker-3
Starting SpawnPoolWorker-2
Starting SpawnPoolWorker-4
Pool outputs: [0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
自己寫個了東西,便于自己加深印象:
from multiprocessing import Pool
from time import *
def delay_1(i):
print('delay_one start{}'.format(i), ctime())
sleep(2)
print('delay_one end{}'.format(i), ctime())
def delay_2(i):
print('delay_two start{}'.format(i), ctime())
sleep(4)
print('delay_two end{}'.format(i), ctime())
if __name__ == '__main__':
print('all start', ctime())
pool = Pool()
# 電腦是雙核的,process=2,可以不用寫
# 設(shè)置process=4真的可以提升速度,但是好像不推薦
pool.map(delay_1, [1, 2, 3, 4])
# 前者結(jié)束后后者開始
pool.map(delay_2, [1, 2])
pool.close()
pool.join()
print('all end', ctime())
輸出結(jié)果:
all start Wed Aug 10 22:44:55 2016
delay_one start1 Wed Aug 10 22:44:55 2016
delay_one start2 Wed Aug 10 22:44:55 2016
delay_one end1 Wed Aug 10 22:44:57 2016
delay_one start3 Wed Aug 10 22:44:57 2016
delay_one end2 Wed Aug 10 22:44:57 2016
delay_one start4 Wed Aug 10 22:44:57 2016
delay_one end3 Wed Aug 10 22:44:59 2016
delay_one end4 Wed Aug 10 22:44:59 2016
delay_two start1 Wed Aug 10 22:44:59 2016
delay_two start2 Wed Aug 10 22:44:59 2016
delay_two end2 Wed Aug 10 22:45:03 2016
delay_two end1 Wed Aug 10 22:45:03 2016
all end Wed Aug 10 22:45:03 2016
進(jìn)程池是個什么東西呢?可以看到pool.map(func,literal)的用法就是后面可迭代數(shù)據(jù)加到前面func中,本來我們一個參數(shù)放到一個函數(shù)運行結(jié)果出來需要2s的話,4個是8s,但是我們開了多進(jìn)程,默認(rèn)雙核,所以進(jìn)程池是兩個處理器處理數(shù)據(jù),也就是說一回可以處理2個,時間減半,只需要4s。這是在需要大量迭代數(shù)據(jù)的進(jìn)程中比較快捷的方法。
pool()之間不阻塞,一個完成以后開啟另一個
2.split的用處
str = """
1
2
3
4
"""
這樣的打出來是有格式的,所以用str.split(),來處理一下,就返回一個列表每一行就是列表的一個元素
3.增加models
因為兩個py(一個a,一個b)中建立pymongo的話,a、b分別初始化的話會覆蓋掉對方,所以增加了models,專用于
數(shù)據(jù)庫初始化,如果在a中要用到models,就在文件a中import models,然后在a中:
直接models.first_grade.save(data)這樣使用。
4.import的一些問題,
如果用到A中的一些函數(shù),一定要一個一個寫出來,不要from A import *,這樣沒人知道你突然用到某個 函數(shù)是從A中import的。
文件test1.py中有兩個函數(shù):a和b,其中b用到了a函數(shù)。在test2中import了test1以后,怎么用a函數(shù)呢?
test1.a()使用,用b也是用test1.b(),但是b用到了a???沒關(guān)系?真的沒關(guān)系!即便在test2中寫from test1 import b,直接用b(),函數(shù)b()也會引用到a(),而不用我們操心去多添加一行from test2 import a(這行是完全沒有必要的)
5.soup.find()的使用
soup.find('a', 'apple')挑選出來的就是<a class='apple'></a>元素,但只是符合的第一個元素,不是列表,如果
是soup.find_all()才選出所有符合的列表
總結(jié),能夠爬取10w級別數(shù)據(jù)是因為這些數(shù)據(jù)的info頁面結(jié)構(gòu)是一樣的。因為對于公司方便,所以對我們也方便。
爬蟲告一段落了,爬蟲真的沒什么難學(xué)的,基本都是套路,習(xí)慣了就好了