Python網頁抓取程式(續)

來源:互聯網
上載者:User

繼續上次的話題,這次抓取的網頁是天涯論壇中,“地緣看世界”

1、擷取網址:通過Regex來擷取各貼子網址

link='http://www.tianya.cn/publicforum/content/worldlook/1/223829.shtml'
    html=urllib2.urlopen(link).read()
    m=re.search(r'name=\'idArticleslist\' value=\S*>',html)
    IDs=re.findall(r'[0-9]+',m.group(0))

for ID in IDs:
        url="http://www.tianya.cn/publicforum/content/worldlook/1/%s.shtml"%ID

2、 下載網頁:以前是邊下載邊處理,這樣處理時間長,有時還有下載不了的情況,改為下載到指定目錄,並在下載前檢查是否存在同名

htmldir=r'.\html\\'

filename=htmldir+url.split('/')[-1]
    if (not os.path.exists(filename)) or os.path.getsize(filename)==0:
        print 'downloading'+filename+'\n'
        html=urlRead(url)
        if len(html)>0:
            f=open(filename,'w')
            f.write(html)
            f.close()

3、下載後對網頁內容進行分析,在分析前要對網頁進行處理以去除htmlparser無法處理的部分,實質是對網頁進行截取,並將無法處理字串替換

txts=re.split(r'<div class="respond" id="adsp_content_replybox_frame_1">',html)
    txt=txts[0]
    txt=re.sub('\xcb\xce\xcc\xe5','\'\xcb\xce\xcc\xe5\'', txt)

4、提取貼子的本文,還是正規的htmlparser的方法,但這種方法速度很慢,也可採用Regex的方法,但這樣適應性不強。文本中也以

這個貼子中有大量的圖片,在<imgsrc=連結地址>的形式儲存

class DocParser(HTMLParser.HTMLParser):
    def __init__(self,pool):
        self.pool=pool
        self.startread=0
        self.pre=0
        HTMLParser.HTMLParser.__init__(self)
        self.doc=''
    def handle_starttag(self, tag, attrs):
        if tag=='span':
            for (name,value) in attrs:
                if name=='value' and value=='10174465':
                    self.pre=1
        if tag=="div" and self.pre==1:
            for (name,value) in attrs:
                if name=='class' and value =='post':
                    self.startread= 1
        if tag=='img' and self.startread==1:
           
            for (name,value) in attrs:
                if name=='original':
                   
                    imgname=value.split('/')[-4]+value.split('/')[-3]\
                            +value.split('/')[-2]+value.split('/')[-1]
                    self.doc+='<imgsrc=%s>\n'%imgname
                    if not os.path.exists(htmldir+imgname):
                        self.pool.add_task(getImg,value,htmldir)
                       
    def handle_endtag(self, tag):
        if tag == 'div' and self.startread==1:
            self.doc+='\n\n\n'
            self.pre=0
            self.startread = 0
    def handle_data(self,data):
        if self.startread:
            self.doc+=data
            self.doc+='\n'

5、破解防外連結:通過設定Referer實現

preurl='http://www.tianya.cn/'

req = urllib2.Request(url)

req.add_header('Referer', preurl)

6、提高urlopen工作健壯性,設定重試次數和逾時等待

改造後的urlopen如下:

def urlRead(url):
    fails = 0
    rs=''
    preurl='http://www.tianya.cn/'
    while True:
        try:
 
            if fails >= 100:
                print 'Failed to Read '+url
                break
            #設定Referer,避免防盜鏈
            req = urllib2.Request(url)
            req.add_header('Referer', preurl)
            response=urllib2.urlopen(req,timeout=30)
            length=response.info()['Content-Length']
            rs=response.read()
            if len(rs)==length:
                continue
                    
        except Exception:
            fails += 1
            time.sleep(10)
        else:
            break
       
    return rs

7、簡易多線程下載:以前試用過stackless感覺沒有效果,後來還是使用threadpool類,

from Queue import Queue
from threading import Thread

class Worker(Thread):
    """Thread executing tasks from a given tasks queue"""
    def __init__(self, tasks):
        Thread.__init__(self)
        self.tasks = tasks
        self.daemon = True
        self.start()
   
    def run(self):
        while True:
            func, args, kargs = self.tasks.get()
            try: func(*args, **kargs)
            except Exception, e: print e
            self.tasks.task_done()

class ThreadPool:
    """Pool of threads consuming tasks from a queue"""
    def __init__(self, num_threads):
        self.tasks = Queue(num_threads)
        for _ in range(num_threads): Worker(self.tasks)

    def add_task(self,  func, *args, **kargs):
        """Add a task to the queue"""
        self.tasks.put(( func, args, kargs))

    def wait_completion(self):
        """Wait for completion of all the tasks in the queue"""
        self.tasks.join()

使用時:

pool = ThreadPool(200)

for ID in IDs:
       url="http://www.tianya.cn/publicforum/content/worldlook/1/%s.shtml"%ID
       pool.add_task(getHtml,url,htmldir)

pool.wait_completion()

8、輸出到pdf,我使用了reportlab要注意的是:

引用字型:

reportlab.rl_config.warnOnMissingFontGlyphs = 0

pdfmetrics.registerFont(TTFont('YaHei', 'msyh.ttf'))
pdfmetrics.registerFont(TTFont('YaHeiBD', 'msyhbd.ttf'))
fonts.addMapping('YaHei', 0, 0, 'YaHei')
fonts.addMapping('YaHei', 0, 1, 'YaHei')
fonts.addMapping('YaHeiBD', 1, 0, 'YaHeiBD')
fonts.addMapping('YaHeiBD', 1, 1, 'YaHeiBD')
stylesheet=getSampleStyleSheet()
normalStyle = copy.deepcopy(stylesheet['Normal'])
normalStyle.fontName ='YaHei'

其次是中文換行:

normalStyle.wordWrap = 'CJK'

中文的左縮排有bug設定左縮排後,第一行全部向右移,並不是比其他的行前面少幾個字

最後是內嵌圖片:取得圖片的長和寬,然後設定縮放比,

def get_image(path):
    width=439
    height=685
    img = utils.ImageReader(path)
    iw, ih = img.getSize()
   
    if iw>width or ih>height:
        rw=float(iw)/float(width)
        rh=float(ih)/float(height)
        if rw>rh:
            return Image(path,width,round(ih/rw))
        else:
            return Image(path,round(iw/rh),height)
    else:
        return Image(path)

結論:python是處理網頁的利器,但我在編碼上浪費了許多時間,在htmlparser和re中對中文的編碼支援也不好,不知道各達人有沒有什麼好方法。

python號稱是“膠水語言”,但我始終對如何將其與其他諸如C#,java在一起使用感到困惑。

多線程下載還是存在很多問題,各位在借鑒時一定要注意。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.