一個Python小白5個小時爬蟲經歷

hkxj5011 7年前發布 | 40K 次閱讀 Python 網絡爬蟲

前言

最近業余在做一個基于.NET Core的搜索項目,奈何基層代碼寫好了,沒有看起來很華麗的數據供測試。很巧的也是博客搜索,于是乎想到了博客園。C#也能做做頁面數據抓取的,不過在博客園看到的大部分都是python實現,所以就臨時想了一下看看python到底是什么東東,不看基礎語法,不看語言功能,直接上代碼,哪里不會搜哪里。代碼完成總共用時大概4個小時,其中搭建環境加安裝BeautifulSoup大概1個小時。解析HTML用時間最多了,邊看demo邊解析,大概2個小時,剩下的時間就是調試加保存數據了。

環境搭建

既然用python,那么自然少不了語言環境。于是乎到官網下載了3.5版本的。安裝完之后,隨機選擇了一個編輯器叫PyCharm,話說python編輯器還真挺多的。由于本人是小白,所以安裝事項不在過多贅述。

建好項目,打開編輯器,直接開工。本來之前用C#寫的時候,大體思路就是獲取網頁內容,然后正則匹配。后來發現網上的帖子也很多。不過在搜索過程中發現,不建議用正則來匹配HTML。有正好我的正則不太好,所以我就搜了一下HTML解析工具,果不其然,人家都做好了,直接拿來用吧。沒錯就是這個東東: BeautifulSoup 。 安裝也很簡單,不過中間出了個小插曲,就是bs4沒有。繼續搜,然后需要用pip安裝一下就好了。(當然我并不知道ps4和pip是什么鬼)

思路分析

博客嗎,我當然就對準了博客園,于是乎,進入博客園首頁,查看請求。

發送請求

當然我不知道python是怎么進行網絡請求的,其中還有什么2.0和3.0的不同,中間曲曲折折了不少,最終還是寫出了最簡單的一段請求代碼。

importurllib.parse
importurllib.request
 

params  CategoryId=808 CategoryType=SiteHome ItemListActionName=PostList PageIndex=3 ParentCategoryId=0 TotalPostCount=4000

defgetHtml(url,values):     user_agent='Mozilla/5.0 (Windows NT 6.3; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.82 Safari/537.36'     headers = {'User-Agent':user_agent}     data = urllib.parse.urlencode(values)     response_result = urllib.request.urlopen(url+'?'+data).read()     html = response_result.decode('utf-8')     return html  

獲取數據

defrequestCnblogs(index):     print('請求數據')     url = '其實博客園這個請求還是挺標準的,哈哈正好適合抓取。因為他返回的就是一段html。(如果返回json那不是更好。。。。)

數據解析

上文已經提到了,用到的是BeautifulSoup,好處就是不用自己寫正則,只要根據他的語法來寫就好了,在多次的測試之后終于完成了數據的解析。先上一段HTML。然后在對應下面的代碼,也許看起來更輕松一些。

<divclass="post_item">
    <divclass="digg">
        <divclass="diggit" onclick="DiggPost('hyper-xl',6417741,281238,1)">
            <spanclass="diggnum" id="digg_count_6417741">1</span>
        </div>
        <divclass="clear"></div>
        <divid="digg_tip_6417741" class="digg_tip"></div>
    </div>
    <divclass="post_item_body">
        <h3><a class="titlelnk"  target="_blank">Python 字符串格式化</a></h3>
 
 
        <p class="post_item_summary">
            <a  target="_blank">
                <imgwidth="48" height="48" class="pfs"
                    src="http://pic.cnblogs.com/face/795666/20160421231717.png" alt="" />
            </a>    轉載請注明出處 Python2.6+ 增加了str.format函數,用來代替原有的'%'操作符
 
            。它使用比'%'更加直觀、靈活。下面詳細介紹一下它的使用方法。 下面是使用'%'的例子: 格式很像C語言的printf是不是?由于'%'是一個操作符,只能在左右
 
            兩邊各放一個參數,因此右邊多個值需要用元組或 ...
        </p>
 
        <divclass="post_item_foot">
            <a  class="lightblue">新月的力量_141</a>
            發布于 2017-02-19 23:07
            <spanclass="article_comment">
                <a  title="" class="gray">
                    評論(0)
                </a>
            </span>
            <spanclass="article_view">
                <a  class="gray">
                    閱讀
 
                    (138)
                </a>
            </span>
        </div>
    </div>
    <divclass="clear"></div>
</div>

通過上文的HTML代碼可以看到幾點。首先每一條數據都在 div(class=”post_item”)下。然后 div(“post_item_body”)下有用戶信息,標題,鏈接,簡介等信息。逐一根據樣式解析即可。代碼如下:

frombs4importBeautifulSoup
importrequest
importre
 

解析最外層

defblogParser(index):     cnblogs = request.requestCnblogs(index)   soup = BeautifulSoup(cnblogs, 'html.parser')   all_div = soup.find_all('div', attrs={'class': 'post_item_body'}, limit=20)     blogs = []   #循環div獲取詳細信息   for itemin all_div:       blog = analyzeBlog(item)       blogs.append(blog)     return blogs  

解析每一條數據

defanalyzeBlog(item):     result = {}     a_title = find_all(item,'a','titlelnk')     if a_titleis not None:         # 博客標題         result["title"] = a_title[0].string         # 博客鏈接         result["href"] = a_title[0]['href']     p_summary = find_all(item,'p','post_item_summary')     if p_summaryis not None:         # 簡介         result["summary"] = p_summary[0].text     footers = find_all(item,'div','post_item_foot')     footer = footers[0]     # 作者     result["author"] = footer.a.string     # 作者url     result["author_url"] = footer.a['href']     str = footer.text     time = re.findall(r"發布于 .+? .+? ", str)     result["create_time"] = time[0].replace('發布于 ','')       comment_str = find_all(footer,'span','article_comment')[0].a.string     result["comment_num"] = re.search(r'\d+', comment_str).group()       view_str = find_all(footer,'span','article_view')[0].a.string     result["view_num"] = re.search(r'\d+', view_str).group()       return result   deffind_all(item,attr,c):     return item.find_all(attr,attrs={'class':c},limit=1) </code></pre>

上邊一堆代碼下來,著實花費了我不少時間,邊寫邊調試,邊百度~~不過還好最終還是出來了。等數據都整理好之后,然后我把它保存到了txt文件里面,以供其他語言來處理。本來想寫個put直接put到ElasticSearch中,奈何沒成功。后邊在試吧,畢竟我的重點只是導數據,不在抓取這里。

importmatch
importos
importdatetime
importjson
 
defwriteToTxt(list_name,file_path):
    try:
        #這里直接write item 即可,不要自己給序列化在寫入,會導致json格式不正確的問題
        fp = open(file_path,"w+",encoding='utf-8')
        l = len(list_name)
        i = 0
        fp.write('[')
        for itemin list_name:
            fp.write(item)
            if i<l-1:
                fp.write(',\n')
            i += 1
        fp.write(']')
        fp.close()
    exceptIOError:
        print("fail to open file")
 

def getStr(item):

   return json.dumps(item).replace('\'','\"')+',\n'

  defsaveBlogs():     for i in range(1,2):         print('request for '+str(i)+'...')         blogs = match.blogParser(i,5)         #保存到文件         path = createFile()         writeToTxt(blogs,path+'/blog_'+ str(i) +'.json')         print('第'+ str(i) +'頁已經完成')     return 'success'   defcreateFile():     date = datetime.datetime.now().strftime('%Y-%m-%d')     path = '/'+date     if os.path.exists(path):         return path     else:         os.mkdir(path)         return path   result = saveBlogs() print(result) </code></pre>

上邊呢,我取了一百頁的數據,也就是大概2000條做測試。

成果驗收

廢了好大勁終于寫完那些代碼之后呢,就可以享受勝利的果實了,雖然是初學者,代碼寫的很渣,這參考一下,那參考一下,不過還是有些收獲的。運行效果如下:

生成的文件:

文件內容:

總結

一個簡單的抓取程序就寫完了,python還真是TM的好用。以后有空再研究研究吧。代碼行數算上空行和注釋總共  100 (50+25+25) 行。湊個整數好看點~~現在認識字我感覺就可以上手寫程序了。這里百度一下,那里google一下,問題就解決了,程序也出來了,大功告成。

是時候該和python暫時告別了,繼續我的.NET事業。話說上次做rss采集的時候,好多“.NET要完蛋了”,“為什么我們不招.NET” 是什么鬼。 小伙伴們,下次見。

 

來自:http://python.jobbole.com/87566/

 

 本文由用戶 hkxj5011 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!