在开源中国社区中偶然发现了这个:屌丝娱乐(终极版)-->从百度贴吧下载妹子图,于是就按照上面的代码自己改写了一遍。从中主要学习了BeautifulSoup、urllib、threading等三个模块的应用。
1、BeautifulSoup模块(简称BS模块):python的html文档解析器
python2.7中默认没有安装BS模块,在使用该模块之前,先在BeautifulSoup这里下载安装包,我下载的是:beautifulsoup4-4.2.1.tar.g
z,下载完之后解压在一个目录下,然后用bat文件进行安装,bat文件的内容为:
python setup.py install
pause
至此,BS模块的安装完成。类似的PY模块都可以按照上面的方法进行安装。
在用BS对Html文档进行解析之前,我们需要先获得该html文档。如果要解析的文档是一个文件,可以用文件的句柄作为BS初始化的参数;如果解析的文档是一个str,则直接用该str做为BS的参数即可,代码为:
from bs4 import BeautifulSoup
fp = open("index.html" , "r") #打开html文档
soup1 = BeautifulSoup( fp )
soup2 = BeautifulSoup( "<html>data</html>")
得到BS对象之后,对html文档解析最主要的一个步骤就是查找元素。BS提供了find(args1[,args2,args3...])和find_all(
args1[,args2,args3...])两个方法,find用于查找第一个出现的元素对象,返回元素;find_all用于查找所有满足条件的对象,返回一个包含元素的列表。args是查找的参数,可以是条件表达式,也可以是正则表达式。
得到要查找的元素之后,我们还需要获得元素的属性、name、value等信息,假设当前已经查找到元素x,得到各信息的代码为:
x.attrs['href'] 或者 x['href'] #获得元素x的"href"属性的值。
x.name #获得元素的名称
x.text #获得元素的文本
2、urllib模块
在网页处理中,该模块主要有两个比较有用的方法,分别是urlopen和urlretrieve
import urllib
url = "www.google.com"
path = "C:\\test.html"
wp = urllib.urlopen( url )
content = wp.read()
fp = open( path , "w")
fp.write( content )
其中用到的urlopen()打开一个特定的URL字符串与web连接,并返回了文件类的对象。语法结构如下:
urllib.urlopen(url[, data[, proxies]]) :
urlopen()的对象方法如下:
* read() :读取所有内容;
* readline():读出一行;
* readlines() :读出所有行并返回一个列表
* fileno():返回文件句柄
* close():关闭URL的连接
* info():返回一个httplib.HTTPMessage 对象,表示远程服务器返回的头信息;
* getcode():返回Http状态码。如果是http请求,200表示请求成功完成;404表示网址未找到;
* geturl():返回请求的url;
import urllib
def cbk(a, b, c):
'''回调函数
@a: 已经下载的数据块
@b: 数据块的大小
@c: 远程文件的大小
'''
print a , b , c
per = 100.0 * a * b / c
if per > 100:
per = 100
print '%.2f%%' % per
url = "www.google.com"
path = "C:\\test.html"
urllib.urlretrieve( url , path , cbk ) #下载url的资源并存储在path中,可用于下载图片,文档等
Thread 是threading模块中最重要的类之一,可以使用它来创建线程。有两种方式来创建线程:一种是通过继承Thread类,重写它的run方法;另一种是创建一个threading.Thread对象,在它的初始化函数(__init__)中将可调用对象作为参数传入。下面分别举例说明。先来看看通过继承threading.Thread类来创建线程的例子:
import threading
count = 0
class Counter( threading.Thread ):
def __init__( self ,lock ,threadName ):
super( Counter ,self ).__init__( name = threadName )
self.lock = lock
def run( self ):
global count
self.lock.acquire()
for i in range( 1000 ):
count += 1
self.lock.release()
lock = threading.Lock()
for i in range(5) :
Counter( lock , "thread-" + str(i) ).start()
print count
另外一种创建线程的方法为:
import threading
count = 0
lock = threading.Lock()
def doAdd():
global count , lock
lock.acquire()
for i in range(1000):
count += 1
lock.release()
for i in range(5):
threading.Thread( target=doAdd , args=() ,name="thread-"+str(i) ).start()
print count
综合上面的知识,并结合OSChina上的代码,下面的代码实现从httpurl制定的贴吧中下载所有图片,然后保存在当前目录一个叫"DownloadPictrue"的文件夹下面。具体的代码为:
#-*-coding=gbk-*-
from bs4 import BeautifulSoup
import urllib
import re
import threading
import os
titleUrl = {}
chunkNum = 100
def find_title( soup ):
Eab = soup.find_all('a' , target="_blank" , class_="j_th_tit")
for i ,aa in enumerate(Eab) :
titleUrl[i] = baseUrl + aa['href']
#print aa['title'].encode('gbk') , titleUrl[i]
def get_soup_from_url( url ):
mid = urllib.urlopen( url )
ch = mid.read()
return BeautifulSoup( ch )
def get_img_url_from_url( url ):
soup = get_soup_from_url( url )
imgElements = soup.find_all( 'img' , src=re.compile('imgsrc') )
return imgElements
def get_last_name_of_url( url ):
pos = url.rfind('/') ;
return url[ pos+1 : ]
def get_img_from_url( url , path ):
filename = path + os.sep + get_last_name_of_url( url ) ;
fw = open( filename , "wb" ) ;
fc = urllib.urlopen( url ) ;
while True :
chunkD = fc.read( chunkNum * 1024 )
if len( chunkD ) == 0 :
break
fw.write( chunkD )
fw.close()
fc.close()
def get_tie_ba_img_url_from_url( url ):
img = {}
titleHtml = get_soup_from_url( url )
totlePage = titleHtml.find('span' , class_="red")
if totlePage.text == "" :
itotlePage = 1
else:
itotlePage = int( totlePage.text )
img[0] = get_img_url_from_url( url ) ;
for i in range(1 , itotlePage ) :
img[i] = get_img_url_from_url( url + "&pn=" + str(i+1) )
for i in range( itotlePage ) :
for element in img[i] :
threading.Thread( target = get_img_from_url , args = ( element['src'] , path ) ).start()
baseUrl = "http://tieba.baidu.com"
httpurl = "http://tieba.baidu.com/f?kw=%C0%EE%D2%E3"
returnHtml = urllib.urlopen( httpurl )
returnHtml = returnHtml.read()
soup = BeautifulSoup( returnHtml )
find_title( soup )
path = "DownloadPictrue"
if( not os.path.exists( path ) ): os.makedirs( path )
for i in titleUrl :
threading.Thread( target=get_tie_ba_img_url_from_url , args=( titleUrl[i] + "?see_lz=1" , ) ).start()