本文已经将1024真实网址隐去,只介绍整个技术流程。
一、基本概念
1.爬虫:通过程序访问web数据,获取web信息(文字、图片、视频)。
2.爬虫流程:
2.1.获取url:
为了防止网站的反爬取,增加url head列表:
# 定义头列表
my_headers=[
"Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.153 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64; rv:30.0) Gecko/20100101 Firefox/30.0"
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.75.14 (KHTML, like Gecko) Version/7.0.3 Safari/537.75.14",
"Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Win64; x64; Trident/6.0)"
]
如果已知URL,则可以直接使用。如果未知,则还需要先爬取根节点url内容来获取。
2.2.获得界面信息:
def get_content(url,headers):
'''''
@获取403禁止访问的网页
'''
# ra_value = random.randint(0, 0.5)
# time.sleep(ra_value)
randdom_header=random.choice(headers)
req=urllib2.Request(url)
req.add_header("User-Agent",randdom_header)
# req.add_header("Host","blog.csdn.net")
req.add_header("Referer","http://XXXXXXXXXXXXXXXXXXXXXXXXXXX")
req.add_header("GET",url)
content=urllib2.urlopen(req).read()
return content
2.3.信息解析:
信息解析用得是BeautifulSoup,也可用正则表达式,基本的思路就是:将想要的数据信息提取出来
二、爬取流程
1.开启线程池(100页,开100个线程并发)
2.获取每一页的每篇url和文章名称
3.获取每篇文章的图片,并存进本地文件夹
三、代码
# -*- coding: UTF-8 -*-
import urllib
import urllib2
import cookielib
import time
import random
import os
from multiprocessing.dummy import Pool as ThreadPool # 导入多线程库
import sys
reload(sys)
sys.setdefaultencoding('utf8')
import requests
# import request
from bs4 import BeautifulSoup
# 定义头列表
my_headers=[
"Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/35.0.1916.153 Safari/537.36",
"Mozilla/5.0 (Windows NT 6.1; WOW64; rv:30.0) Gecko/20100101 Firefox/30.0"
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_2) AppleWebKit/537.75.14 (KHTML, like Gecko) Version/7.0.3 Safari/537.75.14",
"Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.2; Win64; x64; Trident/6.0)"
]
# url获得页面内容
def get_content(url,headers):
'''''
@获取403禁止访问的网页
'''
# ra_value = random.randint(0, 0.5)
# time.sleep(ra_value)
randdom_header=random.choice(headers)
req=urllib2.Request(url)
req.add_header("User-Agent",randdom_header)
# req.add_header("Host","blog.csdn.net")
req.add_header("Referer","http://XXXXXXXXXXXXXXXXXXX")
req.add_header("GET",url)
content=urllib2.urlopen(req).read()
return content
# 获取第num页的文章的数据:文章url,文章名称(后续以文章名称新建文件夹)
def get_article(data):
article_url_list = []
article_txt_list = []
soup=BeautifulSoup(data ,'html.parser') # BeautifulSoup 解析网页
data_soup = soup.find_all(class_= "tal") # 定位所需信息
# print data_soup
# 从每页找到对应每篇文章的url
for i in range(1,len(data_soup)):
# print ("url:%s"%i)
# htm_data/16/1712/2815482.html
try:
article_txt = str(data_soup[i].find("a").get_text())
# print (article_txt)
article_txt_list.append(article_txt)
href_list = str(data_soup[i].find("a").get("href"))
# print (href_list)
if "htm_data/16" in href_list:
article_url_part = href_list.split("htm_data")[1] # 去除第一个/前面的字符串
# 图片页面
article_url = 'http://XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
article_url_list.append(article_url)
except:
print ("get_article error")
return article_url_list,article_txt_list
# 得到图片的url
def get_picture(article_url, article_txt):
# 有多少篇文章,就建多少个文件夹存入图片
for i in range(len(article_txt)):
# 从每篇文章中找出,对应的图片url
article_data = get_content(article_url[i],my_headers)
article_data_soup=BeautifulSoup(article_data ,'html.parser') # BeautifulSoup 解析网页
# print soup
pir_data = article_data_soup.find(class_= "tpc_content do_not_catch") # 定位所需信息
# print pir_data
pir_list_url = pir_data.find_all("input")
# print pir_list_url
# print(len(pir_data))
# 找到每个图片
for j in range(0,len(pir_list_url)):
print ("pit=%s"%j)
try:
# print pir_list_url[j]
# 获取图片url
#
pir_url = str(pir_list_url[j]).split("src=\"")[1].split("\"")[0] # 进行处理,提取图片链接
print pir_url
# 获取图片
data = get_content(pir_url,my_headers)
# 建立文件夹
path = "E:\WND_ml\\test\\%s\\"%(article_txt[i])
upath = unicode(path,"utf-8") # 转成utf格式
# 判断文件夹是否存在(防止第二次存储图片报错)
if not os.path.exists(upath):
# 如果不存在则创建目录
os.mkdir(upath) # 创建文件夹
f = open(upath+pir_url[-10:],"wb") #以图片名称的后十位字符串命名图片
f.write(data) #写入图片数据到文件夹
f.close() # 做文件夹关闭操作
except Exception,e:
print Exception,":",e
print ("get_picture error")
# 多线程处理函数(处理多个页)
def thread_handl_page(i):
# print ("page:%s"%i)
url = 'http://XXXXXXXXXXXXXXXXXXXX%s'%i
# print url
page = get_content(url,my_headers) # 得到文章列表页面内容
# 获取每页的url,和文章名称list
article_url, article_txt= get_article(page)
print article_url, article_txt
# 存储图片
get_picture(article_url, article_txt)
# 多线程采集循环
# while True:
pool = ThreadPool(101) # 定义线程池数量
thread_list = range(1,101) #线程存放列表
pool.map( thread_handl_page,thread_list )
pool.close()#关闭进程池,不再接受新的进程
pool.join()#主进程阻塞等待子进程的退出
四、要点
1.并发
这里我没有使用爬虫框架,单纯用python的线程池来实现并发(爬取多个页面)。在爬取单个文章的时候,也可并发的爬取多个图片,我代码中没有使用。
2.反爬虫
一般要想一直爬下去,需要使用代理,防止ip被封掉、增加不规律的延时(不建议太高并发,毕竟对网站有压力)、模拟web访问(增加头列表)
将代码中的http换乘实际的1024网址即可测试。