爬虫本质就是模拟浏览器访问
所以理论上平时网页中的操作都可以使用爬虫技术来复原操作
在熟悉HTTP的基础上,可以说是很简单的
爬虫的步骤
1、分析网页
通过F12查看并分析页面,找到需要的数据
如果数据是由JS获得的,就需要使用phantomjs(无头浏览器),selenium(驱动浏览器进行访问)
2、爬取页面
把需要的页面下载下来,解析,得到数据
涉及库:requests(构造访问请求),BeautifulSoup(解析DOM,变成python对象)
3、保存数据
将下载下来的数据保存到本地,数据库、表格、文件
4、分析数据
使用各种库分析数据,生成报表
源码:
设置header属性,User-agent和Referer(通常使用网站主页),模仿浏览器的行为
设置cookies进行session保持,登陆操作基本都会涉及
1 #coding:utf8 2 import requests 3 4 index_url = 'https://dig.chouti.com/' 5 login_url = 'https://dig.chouti.com/login' 6 dianzan_url = 'https://dig.chouti.com/link/vote?linksId=19715301' 7 8 header = { 9 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36', 10 } 11 12 form_data = { 13 'phone':'username', 14 'password':'password', 15 'oneMonth':'1', 16 } 17 18 #创建session对象,发送请求时会携带cookies 19 s = requests.session() 20 #访问首页 21 s.get(index_url,headers = header) 22 #登陆 23 s.post(login_url,form_data,headers = header) 24 #点赞 25 rep = s.post(dianzan_url,'',headers=header) 26 #打印结果 27 print(rep.text) 28 #{"result":{"code":"9999", "message":"推荐成功", "data":{"jid":"cdu_51850864329","likedTime":"1526978335436000" 29 # ,"lvCount":"10","nick":"Flask","uvCount":"5","voteTime":"小于1分钟前"}}}
自动翻页爬取
1 #coding:utf8 2 import requests 3 from bs4 import BeautifulSoup 4 import time 5 6 #多线程爬虫,但没有设置线程数量上限,当页面过多时会消耗过多资源 7 #定义page集合,为了去重 8 page_set = set() 9 10 def get_page(url): 11 global page_set 12 header = { 13 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36', 14 } 15 rep = requests.get('http://www.521609.com/daxuexiaohua'+url, headers=header) 16 soup = BeautifulSoup(rep.text, 'lxml') 17 #找到图片,并找到其img_url 18 imgs = soup.select('.index_img ul a img') 19 for img in imgs: 20 img_url = 'http://www.521609.com' + img.get_attribute_list('src')[0] 21 print('下载图片%s'%img_url) 22 #找到别的页面 23 pages = soup.select('.index_img .listpage a') 24 for page in pages: 25 page_url = '/' + page.get_attribute_list('href')[0] 26 #不是重复页面则访问 27 if page_url not in page_set: 28 page_set.add(page_url) 29 print('正在访问%s' % page_url) 30 #无限递归访问 31 get_page(page_url) 32 33 time_start=time.time() 34 get_page('') 35 time_end=time.time() 36 print('共耗时:%s秒'%(time_end-time_start)) 37 #共耗时:43.121999979秒
多线程貌似会莫名名气的卡死,特别的线程池卡死情况更严重
1 #coding:utf8 2 import threading 3 import requests 4 from bs4 import BeautifulSoup 5 import time 6 7 #多线程爬虫,但没有设置线程数量上限,当页面过多时会消耗过多资源 8 #定义page集合,为了去重 9 page_set = set() 10 lock = threading.Lock() 11 12 def get_page(url): 13 global page_set 14 header = { 15 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36', 16 } 17 rep = requests.get('http://www.521609.com/daxuexiaohua'+url, headers=header) 18 soup = BeautifulSoup(rep.text, 'lxml') 19 #找到图片,并找到其img_url 20 imgs = soup.select('.index_img ul a img') 21 for img in imgs: 22 img_url = 'http://www.521609.com' + img.get_attribute_list('src')[0] 23 #在资源抢占的地方加锁 24 lock.acquire() 25 print('下载图片%s'%img_url) 26 lock.release() 27 #找到别的页面 28 pages = soup.select('.index_img .listpage a') 29 t_list=[] 30 for page in pages: 31 page_url = '/' + page.get_attribute_list('href')[0] 32 #不是重复页面则访问 33 if page_url not in page_set: 34 page_set.add(page_url) 35 lock.acquire() 36 f = open('qq.txt','a+') 37 f.write('正在访问%s ' % page_url) 38 f.close() 39 print('正在访问%s' % page_url) 40 lock.release() 41 #无限递归访问 42 #每一次页面访问就开一个线程 43 task = threading.Thread(target=get_page, args=(page_url,)) 44 task.start() 45 t_list.append(task) 46 for t in t_list: 47 t.join() 48 49 50 time_start=time.time() 51 get_page('') 52 time_end=time.time() 53 print('共耗时:%s秒'%(time_end-time_start)) 54 #共耗时:4.117000103秒
推荐使用,开销小,配置简单
1 from gevent import monkey 2 monkey.patch_all() 3 from gevent.pool import Pool 4 import gevent 5 import requests 6 from bs4 import BeautifulSoup 7 import time 8 9 #协程的方式 10 #定义page集合,为了去重 11 page_set = set() 12 13 14 def get_page(url): 15 global page_set 16 header = { 17 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36', 18 } 19 rep = requests.get('http://www.521609.com/daxuexiaohua'+url, headers=header) 20 soup = BeautifulSoup(rep.text, 'lxml') 21 #找到图片,并找到其img_url 22 imgs = soup.select('.index_img ul a img') 23 for img in imgs: 24 img_url = 'http://www.521609.com' + img.get_attribute_list('src')[0] 25 #在资源抢占的地方加锁 26 print('下载图片%s'%img_url) 27 #找到别的页面 28 pages = soup.select('.index_img .listpage a') 29 g_list=[] 30 for page in pages: 31 page_url = '/' + page.get_attribute_list('href')[0] 32 #不是重复页面则访问 33 if page_url not in page_set: 34 page_set.add(page_url) 35 print('正在访问%s' % page_url) 36 #无限递归访问 37 #每一次页面访问就开一个线程 38 g = gevent.spawn(get_page,page_url) 39 g_list.append(g) 40 for g1 in g_list: 41 g1.join() 42 43 44 time_start=time.time() 45 get_page('') 46 time_end=time.time() 47 print('共耗时:%s秒'%(time_end-time_start)) 48 #共耗时:4.104735612869263秒
保存数据到no-sql数据库redis
爬虫爬到的数据一般不是结构化的,使用key-value的方式保存更合适,而且更快
1 #coding:utf8 2 from gevent import monkey 3 monkey.patch_all() 4 import gevent 5 import requests 6 from bs4 import BeautifulSoup 7 import time 8 import redis 9 10 11 #协程的方式,存储数据到redis 12 #定义page集合,为了去重 13 page_set = set() 14 15 def get_page(url): 16 global page_set 17 header = { 18 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36', 19 } 20 rep = requests.get('http://www.521609.com/daxuexiaohua'+url, headers=header) 21 soup = BeautifulSoup(rep.text, 'lxml') 22 #找到图片,并找到其img_url 23 imgs = soup.select('.index_img ul a img') 24 #连接redis 25 r = redis.Redis(host='127.0.0.1', port='6379') 26 for img in imgs: 27 img_url = 'http://www.521609.com' + img.get_attribute_list('src')[0] 28 img_name = img.get_attribute_list('alt')[0] 29 #储存数据到redis,图片名是key,url是value 30 r.set(img_name,img_url) 31 print('下载图片%s'%img_url) 32 #保存到redis 33 r.save() 34 #找到别的页面 35 pages = soup.select('.index_img .listpage a') 36 g_list=[] 37 for page in pages: 38 page_url = '/' + page.get_attribute_list('href')[0] 39 #不是重复页面则访问 40 if page_url not in page_set: 41 page_set.add(page_url) 42 print('正在访问%s' % page_url) 43 #无限递归访问 44 #每一次页面访问就开一个协程 45 g = gevent.spawn(get_page,page_url) 46 g_list.append(g) 47 for g1 in g_list: 48 g1.join() 49 50 51 time_start=time.time() 52 get_page('') 53 time_end=time.time() 54 print('共耗时:%s秒'%(time_end-time_start)) 55 #共耗时:13.4720001221秒 56 #由于有了数据库的I/O,时间变长了