Python 爬蟲入門課作業(yè)3-爬蟲基礎(chǔ)

課程作業(yè)

  • 選擇第二次課程作業(yè)中選中的網(wǎng)址
  • 爬取該頁面中的所有可以爬取的元素宝与,至少要求爬取文章主體內(nèi)容
  • 可以嘗試用lxml爬取

作業(yè)網(wǎng)址

http://www.reibang.com/p/e0bd6bfad10b

網(wǎng)頁爬取

分別用Beautiful Soup和lxml做了爬蓉抑觥:

  • 主頁面所有鏈接湿酸,寫到 _all_links.txt文件
  • 分別抓取各鏈接帕膜,獲取文章主體內(nèi)容和title, 并保存主體內(nèi)容到以title命名
    的文件
  • 對(duì)于無title或無主體內(nèi)容的鏈接切厘,將url寫到Title_Is_None.txt文件中

最后的輸出圖:


輸出

框架結(jié)構(gòu):

  • spidercomm.py: 定義一些公用函數(shù)珊皿,如寫文件网缝,下載頁面等,這些函數(shù)獨(dú)立于實(shí)際使用的爬取方式

  • spiderbs4.py: 定義用BeautifulSoup實(shí)現(xiàn)需要的一些函數(shù)蟋定,如爬取鏈接寄疏,爬取頁面內(nèi)容

  • spiderlxml.py: 定義用lxml實(shí)現(xiàn)需要的一些函數(shù),如爬取鏈接愉老,爬取頁面內(nèi)容

  • bs4.py: 用BeautifulSoup實(shí)現(xiàn)的爬取客戶端

  • lxml.py: 用lxml實(shí)現(xiàn)的爬取客戶端

文件夾結(jié)果圖:

圖片.png

BeautifulSoup 實(shí)現(xiàn)

BeautifulSoup實(shí)現(xiàn)代碼

1 導(dǎo)入 spidercomm 和 BeautifulSoup 模塊

# -*- coding: utf-8 -*-
import spidercomm as common
from bs4 import BeautifulSoup

2 使用BeautifulSoup 找到所有tag a,spidercomm 模塊的爬取所有鏈接的方法會(huì)用到其返回值豆瘫。

# get all tags a from a single url
def a_links(url_seed,attrs={}):
    html = common.download(url_seed)
    soup = BeautifulSoup(html,'html.parser')
    alinks= soup.find_all('a',attrs)
    return alinks

3 使用BeautifulSoup 爬取某個(gè)url的頁面俊扳,主要關(guān)注title和文章主體。

def crawled_page(crawled_url):
        html = common.download(crawled_url)
        soup = BeautifulSoup(html,'html.parser')
        title = soup.find('h1',{'class':'title'})
        if title== None:
            return "Title_Is_None",crawled_url
        content = soup.find('div',{'class':'show-content'})
        if content == None:
            return title.text, "Content_Is_None"
        return title.text,content.text

4 判斷是否分頁

def isMultiPaged(url):    
    html_page1 = common.download(url % 1)
    soup = BeautifulSoup(html_page1,'html.parser')
    body1 = soup.find('body')   
    body1.script.decompose()
       
    html_page2 = common.download(url % 2)
    if html_page2 == None:
        return False
    soup = BeautifulSoup(html_page2,"html.parser")
    body2 = soup.find('body')
    #print [x.extract() for x in body2.findAll('script') ]
    body2.script.decompose()
    if str(body1) == str(body2):
        return False
    else:
        return True

5 獲取所有分頁數(shù)

def getNumberOfPages(url):
    count = 1
    flag = True
    if (isMultiPaged(url)):
        while flag:
            url= url % count
            # print "url: %s" % url
            count += 1
            html = common.download(url)
            if html==None:
                break        
    return count

BeautifulSoup客戶端代碼

1 導(dǎo)入spidercomm 和 spiderbs4 模塊

# -*- coding: utf-8 -*-
import os
import spiderbs4 as bs4
import spidercomm as common

2 設(shè)置所需的變量促王,創(chuàng)建輸出結(jié)果路徑

# set up             
url_root = 'http://www.reibang.com/'
url_seed = 'http://www.reibang.com/p/e0bd6bfad10b?page=%d'
spider_path='spider_res/bs4/'
if os.path.exists(spider_path) == False:
    os.makedirs(spider_path)

3 調(diào)用spidercomm的getNumberOfPages方法犀盟,判斷要爬取的頁面是否分頁

# get total number of pages
print "url %s has multiple pages? %r" % (url_seed,bs4.isMultiPaged(url_seed))
page_count = bs4.getNumberOfPages(url_seed)
print "page_count is %s" % page_count

4 調(diào)用spidercomm的to_be_crawled_links方法,對(duì)所要爬取的頁面獲取所有鏈接蝇狼,如果有分頁阅畴,則分別獲取各頁并歸并獲取的鏈接,并最終將所有鏈接寫入_all_links.txt文件

# get all links to be crawled and write to file    
links_to_be_crawled=set()
for count in range(page_count):
    links = common.to_be_crawled_links(bs4.a_links(url_seed % count),count,url_root,url_seed)
    print "Total number of all links is %d" % len(links)
    links_to_be_crawled = links_to_be_crawled | links
with open(spider_path+"_all_links.txt",'w+') as file:
    file.write("\n".join(unicode(link).encode('utf-8',errors='ignore') for link in links_to_be_crawled))

5 循環(huán)所獲取的鏈接列表迅耘,爬取每個(gè)鏈接的頁面title和頁面文章內(nèi)容贱枣,分別寫入以title命名的文件中,如無title颤专,則寫入Title_Is_None.txt文件中纽哥。

# capture desired contents from crawled_urls
if len(links_to_be_crawled) >= 1:
    for link in links_to_be_crawled:           
      title,content=bs4.crawled_page(link) 
      # print "title is %s" % title                
      file_name = spider_path + title +'.txt'
      common.writePage(file_name,content)

lxml 實(shí)現(xiàn)

lxml 實(shí)現(xiàn)代碼

1 導(dǎo)入lxml模塊

# -*- coding: utf-8 -*-
import spidercomm as common
import urlparse
from lxml import etree

2 使用lxml找到所有tag a,spidercomm 模塊的爬取所有鏈接的方法會(huì)用到其返回值。

# get all tags a from a single url
def a_links(url_seed,attrs={}):
    html = common.download(url_seed)
    tree = etree.HTML(html)
    alinks= tree.xpath("http://a")
    return alinks

3 調(diào)用spidercomm的getNumberOfPages方法栖秕,判斷要爬取的頁面是否分頁

def crawled_page(crawled_url):
        html = common.download(crawled_url)
        tree = etree.HTML(html)
        title= tree.xpath("/html/body/div[1]/div[1]/div[1]/h1")
        if title == None or len(title) == 0:
            return "Title_Is_None",crawled_url
        contents = tree.xpath("/html/body/div[1]/div[1]/div[1]/div[2]/*")
        if contents == None or len(contents) ==0:
            return title.text, "Content_Is_None"
        content = ''
        for x in contents:
            if (x.text != None):
                content = content + x.xpath('string()')
        return title[0].text,content

4 判斷是否分頁

def isMultiPaged(url):    
    html_page1 = common.download(url % 1)
    tree = etree.HTML(html_page1)    
    xp1 = tree.xpath("/html/body/div[1]/div[1]/div[1]/div[2]/*")
    xp1 = ",".join(x.text for x in xp1)
    html_page2 = common.download(url % 2)
    if html_page2 == None:
        return False
    tree = etree.HTML(html_page2)    
    xp2 = tree.xpath("/html/body/div[1]/div[1]/div[1]/div[2]/*")
    xp2 = ",".join(x.text for x in xp2)
    if xp1 == xp2:
        return False
    else:
        return True

5 獲取所有分頁數(shù)

def getNumberOfPages(url):
    count = 1
    flag = True
    if (isMultiPaged(url)):
        while flag:
            url= url % count
            print "url: %s" % url
            count += 1
            html = common.download(url)
            if html==None:
                break        
    return count   

lxml 客戶端代碼

同前面的bs4客戶端春塌,只是導(dǎo)入的是spiderlxml模塊及調(diào)用。

公用方法代碼

1 導(dǎo)入所需模塊

# -*- coding: utf-8 -*-
import urllib2
import time
import urlparse

2 下載頁面

def download(url,retry=2):
   # print "downloading %s" % url
    header = {
            'User-Agent':'Mozilla/5.0'
            }
    try:
        req = urllib2.Request(url,headers=header)
        html = urllib2.urlopen(req).read()
    except urllib2.HTTPError as e:
            print "download error: %s" % e.reason
            html = None
            if retry >0:
                print e.code
                if hasattr(e,'code') and 500 <= e.code < 600:
                    print e.code
                    return download(url,retry-1)
                    time.sleep(1)
    return html

3 將爬取內(nèi)容寫入文件

def writePage(filename,content):
    content = unicode(content).encode('utf-8',errors='ignore')+"\n"
    if ('Title_Is_None.txt' in filename):
        with open(filename,'a') as file:
            file.write(content)
    else:
        with open(filename,'wb+') as file:
            file.write(content)

4 獲取單一url的所有外鏈接

# get urls to be crawled
#:param alinks: list of tag 'a' href, dependent on implementation eg. bs4,lxml
def to_be_crawled_link(alinks,url_seed,url_root):
    links_to_be_crawled=set()
    if len(alinks)==0:
        return links_to_be_crawled
    print "len of alinks is %d" % len(alinks)
    for link in alinks:
        link = link.get('href')            
        if link != None and 'javascript:' not in link:
            if link not in links_to_be_crawled:
                realUrl = urlparse.urljoin(url_root,link)
                links_to_be_crawled.add(realUrl)
    return links_to_be_crawled

5 獲取指定分頁的所有外連接

def to_be_crawled_links(alinks,count,url_root,url_seed):
    url = url_seed % count
    links = to_be_crawled_link(alinks,url_root,url)#,{'class':'title'})
    links.add(url)
    return links

結(jié)語:

實(shí)現(xiàn)的還很粗糙,抓取的內(nèi)容也很簡(jiǎn)單只壳,希望和大家一起討論俏拱,并進(jìn)一步完善框架。

兩種實(shí)現(xiàn)爬取下來的頁面內(nèi)容似乎差不多吼句,格式有些差別锅必,bs4的要好一些,可能是自己代碼沒處理好惕艳,需要再研究下搞隐,以后要完善的地方還好多,作業(yè)先提交吧远搪。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末劣纲,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子谁鳍,更是在濱河造成了極大的恐慌味廊,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,807評(píng)論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件棠耕,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡柠新,警方通過查閱死者的電腦和手機(jī)窍荧,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,284評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來恨憎,“玉大人蕊退,你說我怎么就攤上這事°究遥” “怎么了瓤荔?”我有些...
    開封第一講書人閱讀 169,589評(píng)論 0 363
  • 文/不壞的土叔 我叫張陵,是天一觀的道長钥组。 經(jīng)常有香客問我输硝,道長,這世上最難降的妖魔是什么程梦? 我笑而不...
    開封第一講書人閱讀 60,188評(píng)論 1 300
  • 正文 為了忘掉前任点把,我火速辦了婚禮,結(jié)果婚禮上屿附,老公的妹妹穿的比我還像新娘郎逃。我一直安慰自己,他們只是感情好挺份,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,185評(píng)論 6 398
  • 文/花漫 我一把揭開白布褒翰。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪优训。 梳的紋絲不亂的頭發(fā)上朵你,一...
    開封第一講書人閱讀 52,785評(píng)論 1 314
  • 那天,我揣著相機(jī)與錄音型宙,去河邊找鬼撬呢。 笑死,一個(gè)胖子當(dāng)著我的面吹牛妆兑,可吹牛的內(nèi)容都是我干的魂拦。 我是一名探鬼主播,決...
    沈念sama閱讀 41,220評(píng)論 3 423
  • 文/蒼蘭香墨 我猛地睜開眼搁嗓,長吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼芯勘!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起腺逛,我...
    開封第一講書人閱讀 40,167評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤荷愕,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后棍矛,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體安疗,經(jīng)...
    沈念sama閱讀 46,698評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,767評(píng)論 3 343
  • 正文 我和宋清朗相戀三年够委,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了荐类。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,912評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡茁帽,死狀恐怖玉罐,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情潘拨,我是刑警寧澤吊输,帶...
    沈念sama閱讀 36,572評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站铁追,受9級(jí)特大地震影響季蚂,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜琅束,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,254評(píng)論 3 336
  • 文/蒙蒙 一癣蟋、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧狰闪,春花似錦疯搅、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,746評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽罪治。三九已至,卻和暖如春礁蔗,著一層夾襖步出監(jiān)牢的瞬間觉义,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,859評(píng)論 1 274
  • 我被黑心中介騙來泰國打工浴井, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留晒骇,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,359評(píng)論 3 379
  • 正文 我出身青樓磺浙,卻偏偏與公主長得像洪囤,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子撕氧,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,922評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容

  • 本文分享的大體框架包含以下三部分 (1)首先介紹html網(wǎng)頁瘤缩,用來解析html網(wǎng)頁的工具xpath(2)介紹pyt...
    不忘初心c閱讀 2,560評(píng)論 0 14
  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,332評(píng)論 25 707
  • 聲明:本文講解的實(shí)戰(zhàn)內(nèi)容,均僅用于學(xué)習(xí)交流伦泥,請(qǐng)勿用于任何商業(yè)用途剥啤! 一、前言 強(qiáng)烈建議:請(qǐng)?jiān)陔娔X的陪同下不脯,閱讀本文...
    Bruce_Szh閱讀 12,727評(píng)論 6 28
  • 發(fā)個(gè)功夫
    juncheung閱讀 144評(píng)論 0 0
  • 從事嬰幼兒早期教育快兩年之久防楷,可以說也接觸過上千個(gè)0-3歲嬰幼兒富腊,對(duì)0-3歲嬰幼兒早期教育的重要性有一些想法分...
    Merphy1閱讀 1,824評(píng)論 5 1