精华内容
参与话题
问答
  • Python 网络爬虫实战:爬取人民日报新闻文章

    万次阅读 多人点赞 2019-05-11 22:44:04
    昨天晚上,我一好哥儿们找我帮忙,他的一个课题中需要爬取《人民日报》中的文章,方便后续对文章内容进行分词,词性标注,词频统计等等一系列数据统计和分析。于是他便找到了我。 关于爬虫的大致需求如下,我简单看...

    昨天晚上,我一好哥儿们找我帮忙,他的一个课题中需要爬取《人民日报》中的文章,方便后续对文章内容进行分词,词性标注,词频统计等等一系列数据统计和分析。于是他便找到了我。

    关于爬虫的大致需求如下,我简单看了一下这个网站和他要爬的东西,难度不是很大,但涉及到的知识也挺全面的,正好拿来练练手,于是一口答应下来。

     

    写爬虫之前,先回顾一下爬取的思路。

    首先,要 明确自己要爬取什么内容 ,需求明确了,后面才能有的放矢;然后,要 分析目标网站,包括 URL 结构,HTML 页面,网络请求及返回的结果等,目的就是要找到我们要爬取的目标位于网站的哪一个位置,我们如何才能获取到,从而指定爬取策略;接下来,就是 编码环节 了,使用代码去发起网络请求,解析网页内容,提取目标数据,并进行数据存储;最后,测试代码,完善程序,如添加一些输入输出的交互,使程序使用更加方便,添加异常捕获和处理的部分,使程序的鲁棒性更佳等。


    一、明确需求

    他的需求其实很简单,就是人民日报每天有一份报纸,每份报纸中有若干个版面,每个版面有若干文章。他希望将这些文章全部爬取下来,按一定的规则存储在本地(具体要求如下图所示)。

     

    二、分析目标网站 

    1.  URL 组成结构 

    人民日报网站的 URL 的结构还是比较直观的,基本上什么重要的参数,比如日期,版面号,文章编号什么的,都在 URL 中有所体现,构成的规则也很简单,像这样

    版面目录:http://paper.people.com.cn/rmrb/html/2019-05/06/nbs.D110000renmrb_01.htm

    文章内容:http://paper.people.com.cn/rmrb/html/2019-05/06/nw.D110000renmrb_20190506_5-01.htm

    在版面目录的链接中,“/2019-05/06/” 表示日期,后面的 “_01” 表示这是第一版面的链接。

    在文章内容的链接中,“/2019-05/06/” 表示日期,后面的 “_20190506_5_01” 表示这是 2019 年 5 月 6 日报纸的第 1 版第 5 篇文章

    值得注意的是,在日期的 “月” 和 “日” 以及 “版面号” 的数字,若小于 10,需在前面补 “0” ,而文章的篇号则不必。

    了解到这个之后,我们可以按照这个规则,构造出任意一天报纸中人一个版面的链接,以及任意一篇文章的链接。

    如:2018 年 6 月 5 日第 4 版的目录链接为:

    http://paper.people.com.cn/rmrb/html/2019-05/06/nbs.D110000renmrb_01.htm

    2018 年 6 月 1 日第 2 版第 3 篇文章的链接为:

    http://paper.people.com.cn/rmrb/html/2018-06/01/nw.D110000renmrb_20180601_3-02.htm

    点击访问,发现果然是这样。至此,网站的 URL 组成结构分析完成。

     

    2.  分析网页 HTML 结构

    在 URL 分析中,我们也发现了,网站的页面跳转是通过 URL 的改变完成的,不涉及到诸如 Ajax 这样的动态加载方法。也就是说,它的所有数据是一开始就加载好的,我们只需要去 html 中提取相应得数据即可。

    PS:如果是使用了 Ajax的话,它网站一开始展示的数据是不全的,只有在你触发了某些操作,如页面浏览到最底部,或者点击查看更多按钮等等等等后,它才会向服务器发出请求,获取剩余的其他数据。如果是这种方式的话,我们的爬取策略也就不是从 HTML 中找了,而是直接向服务器发请求,然后解析服务器返回的 json 文件了,具体方法可以参考《Python网络爬虫实战:爬取知乎话题下 18934 条回答数据》。

    好了,言归正传,我们来分析一下我们的目标网站。按 F12 召唤出开发者工具(点击图中 1 处的小箭头,然后点击网页中的内容,可以在 html 源码中快速找到相应的位置)。

    通过这种方法,我们可以知道,版面目录存放在一个 id = “pageList” 的 div 标签下,class = “right_title1” 或 “right_title2” 的 div 标签中,每一个 div 表示一个版面,而版面的链接就在 id = “pageLink” 的 a 标签中。

    使用同样的方法,我们可以知道,文章目录存放在一个 id = “titleList” 的 div 标签下的 ul 标签中,其中每一个 li 标签表示一篇文章,而文章的链接就在 li 标签下的 a 标签中。

    进入文章内容页面之后,我们可以知道,文章标题存放在 h1 ,h2 ,h3 标签中(有的文章标题只用到了 h1 标签,而有的文章有副标题可能会用到 h2 或 h3 标签), 正文部分存放在 id = “ozoom” 的 div 标签下的 p 标签里。

    至此,目标网站的 HTML 页面分析完成。

     

    3. 制定爬取策略

    通过分析 URL 组成结构以及目标网站的 HTML 结构,我们已经完成了爬虫的前期调研工作,接下来需要根据网站的特点制定相应的爬取策略,然后评估每种方法的优劣和难易程度,最终选择一种最佳方案,进行编码实现。

    策略一:第一遍,先爬取版面目录,将每一个版面的链接保存下来;第二遍,依次访问每一个版面的链接,将该版面的文章链接保存下来;第三遍,依次访问每一个文章链接,将文章的标题和正文保存到本地。

    策略二:由于我们已经知道了文章链接的构成方式,所以我们或许可以跳过目录的爬取,直接循环构造文章链接,爬取文章内容。

    经过一番比较,以及简单的编码测试,我决定使用策略一来完成此爬虫。

    主要原因是,虽然策略二逻辑比较简单也比较方便,但是需要解决两个问题,1. 每天的报纸版面数不同,而且每个版面的文章数也不同,在构造 URL 的时候,如何保证文章不重不漏?2. 有些特殊情况下,文章的编号并不是连续的,该如何解决这个问题?

    所以,综合考虑,我觉得策略一可能会更加稳定更加保险一些(如果大家想到了解决策略二问题的方法,可以尝试一下,或者如果想到有其他策略,也欢迎留言,我们一起探讨)。

     

    三、编码环节

    接下来就到了实际编码环节了,话不多说,直接开始。

    首先导入本项目用到的库:

    import requests
    import bs4
    import os
    import datetime
    import time

    其中,requests 库主要用来发起网络请求,并接收服务器返回的数据;bs4 库主要用来解析 html 内容,是一个非常简单好用的库;os 库主要用于将数据输出存储到本地文件中。

    def fetchUrl(url):
        '''
        功能:访问 url 的网页,获取网页内容并返回
        参数:目标网页的 url
        返回:目标网页的 html 内容
        '''
        
        headers = {
            'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
            'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36',
        }
        
        r = requests.get(url,headers=headers)
        r.raise_for_status()
        r.encoding = r.apparent_encoding
        return r.text
    

    fetchUrl 函数用于发起网络请求,它可以访问目标 url ,获取目标网页的 html 内容并返回。

    这里其实是应该做异常捕获的(我为了简单就省掉了,吐舌头)。因为网络情况比较复杂,可能会因为各种各样的原因而访问失败, r.raise_for_status() 这句代码其实就是在判断是否访问成功的,如果访问失败,返回的状态码不是 200 ,执行到这里时会直接抛出相应的异常。

    def getPageList(year, month, day):
        '''
        功能:获取当天报纸的各版面的链接列表
        参数:年,月,日
        '''
        url = 'http://paper.people.com.cn/rmrb/html/' + year + '-' + month + '/' + day + '/nbs.D110000renmrb_01.htm'
        html = fetchUrl(url)
        bsobj = bs4.BeautifulSoup(html,'html.parser')
        pageList = bsobj.find('div', attrs = {'id': 'pageList'}).ul.find_all('div', attrs = {'class': 'right_title-name'})
        linkList = []
        
        for page in pageList:
            link = page.a["href"]
            url = 'http://paper.people.com.cn/rmrb/html/'  + year + '-' + month + '/' + day + '/' + link
            linkList.append(url)
        
        return linkList

     getPageList 函数,用于爬取当天报纸的各版面的链接,将其保存为一个数组,并返回。

    def getTitleList(year, month, day, pageUrl):
        '''
        功能:获取报纸某一版面的文章链接列表
        参数:年,月,日,该版面的链接
        '''
        html = fetchUrl(pageUrl)
        bsobj = bs4.BeautifulSoup(html,'html.parser')
        titleList = bsobj.find('div', attrs = {'id': 'titleList'}).ul.find_all('li')
        linkList = []
        
        for title in titleList:
            tempList = title.find_all('a')
            for temp in tempList:
                link = temp["href"]
                if 'nw.D110000renmrb' in link:
                    url = 'http://paper.people.com.cn/rmrb/html/'  + year + '-' + month + '/' + day + '/' + link
                    linkList.append(url)
        
        return linkList

      getPageList 函数,用于爬取当天报纸的某一版面的所有文章的链接,将其保存为一个数组,并返回。

    def getContent(html):
        '''
        功能:解析 HTML 网页,获取新闻的文章内容
        参数:html 网页内容
        '''    
        bsobj = bs4.BeautifulSoup(html,'html.parser')
        
        # 获取文章 标题
        title = bsobj.h3.text + '\n' + bsobj.h1.text + '\n' + bsobj.h2.text + '\n'
        #print(title)
        
        # 获取文章 内容
        pList = bsobj.find('div', attrs = {'id': 'ozoom'}).find_all('p')
        content = ''
        for p in pList:
            content += p.text + '\n'      
        #print(content)
        
        # 返回结果 标题+内容
        resp = title + content
        return resp
    

    getContent 函数,用于访问文章内容页,爬取文章的标题和正文,并返回。

    def saveFile(content, path, filename):
        '''
        功能:将文章内容 content 保存到本地文件中
        参数:要保存的内容,路径,文件名
        '''
        # 如果没有该文件夹,则自动生成
        if not os.path.exists(path):
            os.makedirs(path)
            
        # 保存文件
        with open(path + filename, 'w', encoding='utf-8') as f:
            f.write(content)
    

    saveFile 函数用于将文章内容保存到本地的指定文件夹中。

    def download_rmrb(year, month, day, destdir):
        '''
        功能:爬取《人民日报》网站 某年 某月 某日 的新闻内容,并保存在 指定目录下
        参数:年,月,日,文件保存的根目录
        '''
        pageList = getPageList(year, month, day)
        for page in pageList:
            titleList = getTitleList(year, month, day, page)
            for url in titleList:
                
                # 获取新闻文章内容
                html = fetchUrl(url)
                content = getContent(html)
                
                # 生成保存的文件路径及文件名
                temp = url.split('_')[2].split('.')[0].split('-')
                pageNo = temp[1]
                titleNo = temp[0] if int(temp[0]) >= 10 else '0' + temp[0]
                path = destdir + '/' + year + month + day + '/'
                fileName = year + month + day + '-' + pageNo + '-' + titleNo + '.txt'
                
                # 保存文件
                saveFile(content, path, fileName)
    

    download_rmrb 函数是需求中要求的主函数,可以根据 year,month,day 参数,下载该天的全部报纸文章内容,并按照规则保存在指定的路径 destdir 下。

                
    if __name__ == '__main__':
        '''
        主函数:程序入口
        '''
        year = "2019"
        month = "05"
        day = "06"
        destdir = "D:/data"
    
        download_rmrb(year, month, day, destdir)
        print("爬取完成:" + year + month + day)

    至此,程序的主体功能已经完成。

     

    四、完善程序

    通过上一章节的编码,我们已经实现了 通过调用 download_rmrb 函数,来下载特定日期的全部文章内容。但是同时我们也可以发现,在程序入口 main 函数中,日期是在代码中写死的,也就是说,如果我们想爬取其他日期的报纸,就必须修改源码。

    很不方便不是嘛,我们把它做一下改进,日期使用交互式的方式由用户输入。 

                
    if __name__ == '__main__':
        '''
        主函数:程序入口
        '''    
        # 爬取指定日期的新闻
        newsDate = input('请输入要爬取的日期(格式如 20190502 ):')
    
        year = newsDate[0:4]
        month = newsDate[4:6]
        day = newsDate[6:8]
    
        download_rmrb(year, month, day, 'D:/data')
        print("爬取完成:" + year + month + day)

     

     

    方便了一些是不是?但是问题又来了,如果我想一次性爬一个月的,或者一年的怎么办?我岂不是要手动输入几十次几百次?所以,程序我们还可以改进一下,用户输入其实日期和结束日期,程序爬取期间的日期的所有文章。

    def gen_dates(b_date, days):
        day = datetime.timedelta(days = 1)
        for i in range(days):
            yield b_date + day * i
            
            
    def get_date_list(beginDate, endDate):
        """
        获取日期列表
        :param start: 开始日期
        :param end: 结束日期
        :return: 开始日期和结束日期之间的日期列表
        """
        
        start = datetime.datetime.strptime(beginDate, "%Y%m%d")
        end = datetime.datetime.strptime(endDate, "%Y%m%d")
        
        data = []
        for d in gen_dates(start, (end-start).days):
            data.append(d)
            
        return data
    
                
    if __name__ == '__main__':
        '''
        主函数:程序入口
        '''
        # 输入起止日期,爬取之间的新闻
        beginDate = input('请输入开始日期:')
        endDate = input('请输入结束日期:')
        data = get_date_list(beginDate, endDate)
        
        for d in data:
            year = str(d.year)
            month = str(d.month) if d.month >=10 else '0' + str(d.month)
            day = str(d.day) if d.day >=10 else '0' + str(d.day)
            download_rmrb(year, month, day, 'data')
            print("爬取完成:" + year + month + day)
    #         time.Sleep(3)        # 怕被封 IP 爬一爬缓一缓,爬的少的话可以注释掉

    实际运行测试一下,假设我们要爬取 2019年 4月份的全部报纸内容,那我们在开始日期中输入20190401,在结束日期中输入 20190501,回车运行。

    等待一段时间后,程序便已经运行完成,我们去文件夹中看一下,我们爬到的内容吧。

     爬到的内容整整齐齐的排列在文件夹中,真的是很舒胡啊,随便打开一个文档看一下,也没问题。

     本此爬虫到这里也就算是全部完成了。

     


    写在后面的话

    这次也是很久没有写新的爬虫文章了,一是因为马上要毕业了,忙着做毕业设计;二是写一次教程类的文章确实也是挺辛苦的一件事,要整理思路和语言,要重新整理代码,要各种截图,争取让零基础或者刚入门的人也能看懂并跟着写出来。三是找不到一个有意思的动机,因为爬虫总归是为了用而写的,总不能为了炫技,为了写爬虫而写爬虫吧,那样没有什么意思。

    最一开始写爬虫,是为了记录自己的成长过程,如果自己在学习过程中的这些记录,同时能帮助到更多的后来者,那就更好了。


     2019 年7月10日更新

    有读者在评论中反映说,输入开始和结束日期爬取一段时间内新闻的方法不能用,运行时会报下面的错误。

    我检查了一下,确实是我的疏忽。

    这是因为其中计算日期的函数在 datetime 库中,而我在写博客整理代码的过程中,疏忽忘记了引用这个库,导致程序运行报错。

    解决方法为,在程序中添加两行代码即可:

    import datetime
    import time

    我已经在博客的代码中进行了修改,请大家放心食用。

    感谢 weixin_42435870songxinyueyue 朋友指出问题,十分感谢!!

     

    2020年7月26日更新

    通过读者朋友们的反馈,我发现最近人民日报的网站做了改版,从7月1日起的新闻网页用了新的布局。这也导致了使用原来的代码爬取2020年7月1日之后的新闻时,无法爬取。

    所以这里做一下更新,兼容网站的新格式。

    1. 在 getPageList 函数中,将原来的

        pageList = bsobj.find('div', attrs = {'id': 'pageList'}).ul.find_all('div', attrs = {'class': 'right_title-name'})
    

     改成:

        temp = bsobj.find('div', attrs = {'id': 'pageList'})
        if temp:
            pageList = temp.ul.find_all('div', attrs = {'class': 'right_title-name'})
        else:
            pageList = bsobj.find('div', attrs = {'class': 'swiper-container'}).find_all('div', attrs = {'class': 'swiper-slide'})
    

    2. 在 getTitleList 函数中,将原来的

        titleList = bsobj.find('div', attrs = {'id': 'titleList'}).ul.find_all('li')

    改成:

        temp = bsobj.find('div', attrs = {'id': 'titleList'})
        if temp:
            titleList = temp.ul.find_all('li')
        else:
            titleList = bsobj.find('ul', attrs = {'class': 'news-list'}).find_all('li')

    简单说明一下上面改了什么,

    1. 原网站中,将版面列表和文章列表的标签做了调整,所以我们需要用新的标签新的属性去获取。

    2. 为了兼容,我们先获取之前版本的标签,若可以获取到,则说明是改版前的界面,若获取不到,说明是改版后的界面,需要用新的标签属性去获取。


    如果文章中有哪里没有讲明白,或者讲解有误的地方,欢迎在评论区批评指正,或者扫描下面的二维码,加我微信,大家一起学习交流,共同进步。  

    展开全文
  • Python 爬取内容存入Excel实例

    万次阅读 多人点赞 2018-04-14 09:57:03
    最近老师布置了个作业,爬取豆瓣top250的电影信息。按照套路,自然是先去看看源代码了,一看,基本的信息竟然都有,心想这可省事多了。简单分析了下源代码,标记出所需信息的所在标签,ok,开始干活! 鉴于正则...

           【根据博友们的反馈,博主用python3重新写了一遍,并做了一些改进,点击查看python爬取豆瓣Top250-改进版

           最近老师布置了个作业,爬取豆瓣top250的电影信息。按照套路,自然是先去看看源代码了,一看,基本的信息竟然都有,心想这可省事多了。简单分析了下源代码,标记出所需信息的所在标签,ok,开始干活!

          鉴于正则表达式的资料已经看了不少,所以本次除了beautifulsoup外,还有些re的使用,当然,比较简单。而爬到信息后,以往一般是存到txt文件,或者数据库中,老是重样的操作,难免有些‘厌倦’。心想,干嘛不存到Excel表呢?对啊,可以存到Excel表嘛。。。

          环境准备:pip install openpyxl  (假设你已配好了python环境)

          好了,废话少说,上代码。

        

    # coding=UTF-8
    '''
      function:爬取豆瓣top250的电影信息,并写入Excel文件
    '''
    import requests
    import re
    from openpyxl import workbook  # 写入Excel表所用
    from openpyxl import load_workbook  # 读取Excel表所用
    from bs4 import BeautifulSoup as bs
    import os
    os.chdir('C:\Users\Administrator\Desktop')  # 更改工作目录为桌面
    
    
    def getHtml(src):
        html = requests.get(src).content
        getData(html, src)  # 首页链接和其他页不同,所以单独获取信息
        urls = re.findall('href="(.*filter=?)', html)  # re获取获取跳转链接的href
        for u in range(len(urls) - 2):  # 匹配到的跳转链接最后两个重复,需去掉
            next_url = 'https://movie.douban.com/top250' + urls[u]
            html = requests.get(next_url).content
            getData(html, next_url)
    
    
    def getData(html, num_url):  # html:网页源码 ,num_url:页面链接
        global ws  # 全局工作表对象
        Name = []  # 存储电影名
        Dr = []  # 存储导演信息
        Ma = []  # 存储主演信息
        Si = []  # 存储简介
        R_score = []  # 存储评分
        R_count = []  # 存储评论人数
        R_year = []  # 存储年份
        R_area = []  # 存储地区
        R_about = []  # 存储剧情类型
        soup = bs(html, 'lxml')
        for n in soup.find_all('div', class_='hd'):
            # ts = n.contents[1].text  # 得到电影的所有名称
            ts = n.contents[1].text.strip().split('/')[0]  # 得到电影中文名
            Name.append(ts)
        for p in soup.find_all('p', class_=''):
            infor = p.text.strip().encode('utf-8') #此处用utf-8编码,以免下面查找 ‘主演’下标报错
            ya = re.findall('[0-9]+.*\/?', infor)[0]  # re得到年份和地区
            R_year.append(ya.split('/')[0])  # 得到年份
            R_area.append(ya.split('/')[1])  # 得到地区
            R_about.append(infor[infor.rindex('/') + 1:])  # rindex函数取最后一个/下标,得到剧情类型
            try:
                sub = infor.index('主演')  # 取得主演下标
                Dr.append(infor[0:sub].split(':')[1])  # 得到导演信息
                mh = infor[sub:].split(':')[1]  # 得到主演后面的信息
                Ma.append(re.split('[1-2]+', mh)[0])  # 正则切片得到主演信息
            except:
                print '无主演信息'
                Dr.append(infor.split(':')[1].split('/')[0])
                Ma.append('无介绍...')
        for r in soup.find_all('div', class_='star'):
            rs = r.contents  # 得到该div的子节点列表
            R_score.append(rs[3].text)  # 得到评分
            R_count.append(rs[7].text)  # 得到评论人数
        for s in soup.find_all('span', 'inq'):
            Si.append(s.text)  # 得到简介
        if len(Si) < 25:
            for k in range(25 - len(Si)):
                Si.append('本页有的电影没简介,建议查看核对,链接:' + num_url)
    
        for i in range(25):  # 每页25条数据,写入工作表中
            ws.append([Name[i], R_year[i], R_area[i], R_about[i],
                       Dr[i], Ma[i], R_score[i], R_count[i], Si[i]])
    
    
    if __name__ == '__main__':
        #   读取存在的Excel表测试
        #     wb = load_workbook('test.xlsx') #加载存在的Excel表
        #     a_sheet = wb.get_sheet_by_name('Sheet1') #根据表名获取表对象
        #     for row in a_sheet.rows: #遍历输出行数据
        #         for cell in row: #每行的每一个单元格
        #             print cell.value,
    
        #  创建Excel表并写入数据
        wb = workbook.Workbook()  # 创建Excel对象
        ws = wb.active  # 获取当前正在操作的表对象
        # 往表中写入标题行,以列表形式写入!
        ws.append(['电影名', '年份', '地区', '剧情类型', '导演', '主演', '评分', '评论人数', '简介'])
        src = 'https://movie.douban.com/top250'
        getHtml(src)
        wb.save('test2.xlsx')  # 存入所有信息后,保存为filename.xlsx
    

     

          代码中已有不少注释,这里说下爬取过程中遇到的小问题。

     

           1.soup的contents方法,返回的是某标签下的子节点列表,但刚开始总是取不到想要的值,输出其长度后,有些傻眼..TM什么情况?有这么多的子节点吗?较真的我又去数了几遍,最后发现,它竟然连"换行"都算作是子节点!莫名地有点方...不知各位有没有遇到过。

            

              如图,我按列表下标标记,0,2,4,6,8是换行,但也被算作子节点...

           2.还是contents方法,代码中的 '#得到电影所有名称' 处的代码 n.contents[1]获取的除了a标签外,还有其下的span标签,这是为何?它们算一个整体?

             

           3.对如下图的电影信息处理时,出现了几处错误,原因有以下几点:

              (1)部分电影没有主演信息...

              (2)主演信息为这样'主演: ',就一个主演字样,无内容

              (3)部分电影没有简介

              (4)当主演信息中没有'...'时,获取主演信息受阻

             解决方案:(1)(2)都是主演问题,判断是否存在即可。(我以捕获异常处理)

                           (3)是简介问题,我无法给出具体哪部电影没有简介,但给了该电影所在的页面链接,可访问核查。(貌似有点笨)

                           (4)获取受阻是因为后面没有精确定位点,最后以re.split('[1-2]+')方法解决,匹配年份第一位作为分片点

             

     

              本次分享就到这儿了,最后,照旧放几张结果图吧。(欢迎留言评论,更多openpyxl操作可以点这里查看

             

     

     

     

    博主其他系列文章推荐:

    [1] 【python实用特性】-切片

    [2] 【python实用特性】- 迭代、可迭代对象、迭代器

    [3] 【python实用特性】- 列表生成式

    [4] 【python实用特性】- yield生成器

    [5] Python如何爬取动态网页数据

    [6] Python+selenium实现自动爬取实例

    [7] requests设置请求头、代理

    展开全文
  • 如何快速爬取网页数据(干货)

    万次阅读 2019-09-11 17:25:48
    摘要:对于程序员或开发人员来说,拥有编程能力使得他们构建一个网页数据爬取程序,非常的容易并且有趣。但是对于大多数没有任何编程知识的人来说,最好使用一些网络爬虫软件从指定网页获取特定内容。 网页数据...

    摘要:对于程序员或开发人员来说,拥有编程能力使得他们构建一个网页数据爬取程序,非常的容易并且有趣。但是对于大多数没有任何编程知识的人来说,最好使用一些网络爬虫软件从指定网页获取特定内容。

     

    网页数据爬取是指从网站上提取特定内容,而不需要请求网站的API接口获取内容。“网页数据” 作为网站用户体验的一部分,比如网页上的文字,图像,声音,视频和动画等,都算是网页数据。

     

    对于程序员或开发人员来说,拥有编程能力使得他们构建一个网页数据爬取程序,非常的容易并且有趣。但是对于大多数没有任何编程知识的人来说,最好使用一些网络爬虫软件从指定网页获取特定内容。以下是一些使用八爪鱼采集器抓取网页数据的几种解决方案:

     

    1、从动态网页中提取内容

     

    网页可以是静态的也可以是动态的。通常情况下,您想要提取的网页内容会随着访问网站的时间而改变。通常,这个网站是一个动态网站,它使用AJAX技术或其他技术来使网页内容能够及时更新。AJAX即延时加载、异步更新的一种脚本技术,通过在后台与服务器进行少量数据交换,可以在不重新加载整个网页的情况下,对网页的某部分进行更新。

     

    表现特征为点击网页中某个选项时,大部分网站的网址不会改变;网页不是完全加载,只是局部进行了数据加载,有所变化。这个时候你可以在八爪鱼的元素“高级选项”的“Ajax加载”中可以设置,就能抓取Ajax加载的网页数据了。

     

    八爪鱼中的AJAX设置

     

    2、从网页中抓取隐藏的内容

     

    你有没有想过从网站上获取特定的数据,但是当你触发链接或鼠标悬停在某处时,内容会出现?例如,下图中的网站需要鼠标移动到选择彩票上才能显示出分类,这对这种可以设置“鼠标移动到该链接上”的功能,就能抓取网页中隐藏的内容了。

     

    鼠标移动到该链接上的内容采集方法

     

    3、从无限滚动的网页中提取内容

     

    在滚动到网页底部之后,有些网站只会出现一部分你要提取的数据。例如今日头条首页,您需要不停地滚动到网页的底部以此加载更多文章内容,无限滚动的网站通常会使用AJAX或JavaScript来从网站请求额外的内容。在这种情况下,您可以设置AJAX超时设置并选择滚动方法和滚动时间以从网页中提取内容。

     

    从无限滚动的网页中提取内容

     

    4、从网页中爬取所有链接

     

    一个普通的网站至少会包含一个超级链接,如果你想从一个网页中提取所有的链接,你可以用八爪鱼来获取网页上发布的所有超链接。

     

    5、从网页中爬取所有文本

     

    有时您需要提取HTML文档中的所有文本,即放置在HTML标记(如<DIV>标记或<SPAN>标记)之间的内容。八爪鱼使您能够提取网页源代码中的所有或特定文本。

     

    6、从网页中爬取所有图像

     

    有些朋友有采集网页图片的需求。八爪鱼可以将网页中图片的URL采集,再通过下载使用八爪鱼专用的图片批量下载工具,就能将我们采集到的图片URL中的图片下载并保存到本地电脑中。

    展开全文
  • Python爬虫:彼岸图网图片爬取

    千次阅读 2019-08-15 11:33:17
    1.主要的库: 1.requests 2.Pillow 请自行安装 2.目标网址: http://pic.netbian.com/ ...声明:此网址是随便找的,代码仅供技术交流使用,如有侵权请联系本人删除 ...这就是每个分页的部分URL...

    哈哈,这是我第一篇博客
    半年以后回来再看发现这代码简直太难看了
    现在已经弃用大小驼峰转蛇形命名了
    确实好看
    除了命名别的也写的不怎么样
    因为爬虫只是个爱好所以也不准备再投入时间重构了
    将就着看吧

    1.主要的库:

    1.requests
    2.Pillow
    请自行安装

    2.目标网址:

    http://pic.netbian.com/
    在这里插入图片描述

    声明:此网址是随便找的,代码仅供技术交流使用,如有侵权请联系本人删除

    3.思路

    如何得到每张图片的具体位置呢?

    首先找到在哪一个分页

    打开页面,F12查看源码,我的浏览器是Firefox
    在这里插入图片描述
    然后鼠标移到分页的2上,右键查看元素,可以看到
    在这里插入图片描述
    这就是每个分页的部分URL,验证一下,浏览器中输入 pic.netbian.com/index_5.html ,自动跳转到彼岸图网第五分页在这里插入图片描述
    首页是index.html,分页的部分URL格式为index_[0-9]*.html
    在这里插入图片描述然后在分页中找以缩略图形式显示在页面上的子页面URL
    上图中为/tupian/24556.html

    如果只需要低像素的缩略图的话,现在就可以开始爬了,上图中缩略图图片的部分URL格式为/uploads/allimg/.*a.jpg

    注意区分这两个概念

    如果需要大图,那么就要在/tupian/24556.html下继续去找大图的具体位置。点开缩略图,右击大图,查看元素,找到格式为/uploads/allimg/.*be.jpg的代码,就是这张大图的URL了。

    当然不是所有的大图都是xxxbe.jpg格式的,所以不能用正则匹配be.jpg$的格式去处理,查看子页面中大图代码的位置,都是第一个出现的,其余的都是推荐的相似图片的URL,为了防止重复爬取缩略图图片,可以用正则^/uploads/allimg/.*.jpg去匹配,只要找到一个就break,然后分析下一个子页面的html代码。在这里插入图片描述

    如下,在点开缩略图后还有相似图片推荐,为了不重复抓取,会在代码中作处理在这里插入图片描述

    4.代码

    要写爬虫首先要对Web有一定的了解,要是连查看源码都不会就更别说分析了,所以还是先好好学学Web再去写爬虫,不说会做网页,最起码要能看懂个大概。按我的理解,爬虫实际上就是模拟了浏览器的行为,所以在代码中把上述的步骤实现了就ok

    #coding:gbk
    
    '''
    Author: CSDN wuming7847
    转载请注明出处
    '''
    import requests
    from PIL import Image
    from io import BytesIO
    import re
    from requests.exceptions import HTTPError
    
    root="http://pic.netbian.com/index_%d.html"
    #除首页外所有分页的统一格式
    
    uni="http://pic.netbian.com"
    #子页面和大图的URL前缀
    
    AllPage=[]
    #要爬取的分页URL
    
    AllImgHTML=[]
    #缩略图代表的子页面的部分URL,格式为/tupian/.*.html
    
    AllImgURL=[]
    #每张大图的部分URL,格式为/uploads/allimg/.*.jpg
    
    def GetPageURL(root,Start,counts):
    #得到每个分页的URL放到AllPage中
        if Start==1:
            AllPage.append("http://pic.netbian.com/index.html")
            #将非标准格式的首页URL放入
            for i in range (Start+1,Start+counts):
                newURL=root.replace("%d", str(i))
                AllPage.append(newURL)
        else:   
            for i in range (Start,Start+counts):
                newURL=root.replace("%d", str(i))
                AllPage.append(newURL)
            
    def GetImgHTML(AllPage): 
    #得到每个分页中子页面的URL放到AllImgHTML中     
        for PageURL in AllPage:
            try:
                res=requests.get(PageURL)
                res.raise_for_status()                      
            except HTTPError:
                print("HTTP Error!")
            
            except ConnectionError:
                print("Failed to connect!")
        
            with open("C:\\Users\\PageFile.txt","w",encoding="ISO-8859-1") as PageFile:
                PageFile.write(res.text)
                PageFile.close()
            
            
            with open("C:\\Users\\PageFile.txt","r",encoding="gbk") as ReadFile:           
                str=ReadFile.read()
                mid=re.split("\"", str)
                #用"进行分割,以进行正则表达式匹配
                for i in mid:           
                    ImgHTML=re.findall("^/tupian/.*.html$",i)
                    #提取所有符合格式的str放到ImgHTML中
                    if len(ImgHTML)!=0:
                        AllImgHTML.append(ImgHTML[0])
                        
    def GetImgURL():  
    #得到每个分页中每个子页面的大图的URL放到UsefulImgURL中               
        UsefulImgHTML=[None for i in range(len(AllImgHTML))] 
        #为字符串拼接分配内存  
        for i in range(len(AllImgHTML)):
            UsefulImgHTML[i]=uni+AllImgHTML[i]
        #拼接后得到了可用的子页面URL,格式为http://pic.netbian.com//tupian/.*.html
        
        for html in UsefulImgHTML:
        #对图片组进行请求
            try:
                htmlres=requests.get(html)
                htmlres.raise_for_status()           
            except HTTPError:
                print("HTTP Error!")
            
            except ConnectionError:
                print("Failed to connect!")
                            
            with open("C:\\Users\\ImgHTML.txt","w",encoding="ISO-8859-1") as ImgHTML:
                ImgHTML.write(htmlres.text)
                ImgHTML.close()
            
            with open("C:\\Users\\\ImgHTML.txt","r",encoding="gbk") as ReadHTML:           
                str=ReadHTML.read()
                mid=re.split("\"", str)           
                for i in mid:
                    ImgURL=re.search("^/uploads/allimg/.*.jpg$",i)              
                    if ImgURL is not None:                   
                        AllImgURL.append(ImgURL[0])
                        break
                    #爬到一个大图的URL即break。将每张大图的部分URL存入AllImgURL中,格式为/uploads/allimg/.*.jpg
        
        UsefulImgURL=[None for i in range(len(AllImgURL))]
        #拼接得到最终可供下载的URL放到UsefulImgURL中
        for i in range(len(AllImgURL)):
            UsefulImgURL[i]=uni+AllImgURL[i]
            
        return UsefulImgURL                
        
        
                                           
    def DownloadWallpaper(url,path):
        try:
            res=requests.get(url)
            res.raise_for_status()
            MyImage=Image.open(BytesIO(res.content))
            MyImage.save(path)
            print("Done...")
        except HTTPError:
            print("HTTP Error!")
        except ConnectionError:
            print("Failed to connect!")
            
    
    
    if __name__=="__main__":
        GetPageURL(root, 2, 2)
        GetImgHTML(AllPage)
        UsefulImgURL=GetImgURL()            
        num=[]
        for i in range (len(UsefulImgURL)):
            num.append(i)    
        
        UsefulSavePath=[None for i in range(len(UsefulImgURL))]  
        for i in range(len(UsefulSavePath)):
            UsefulSavePath[i]="C:\\Users\\"+str(num[i])+".jpg"
        for i in range(len(UsefulImgURL)):
            print(i,end=" ")
            DownloadWallpaper(UsefulImgURL[i],UsefulSavePath[i])
        print("Task completed!")
        
        
        
    

    说明:
    1.要爬取从第几页开始的连续几页,就在主函数中修改GetPageURL(root,start,counts)中start和counts的值
    2.自己改存放路径,windows下文件操作的路径是\\而非\
    3.图片的名字都是[0-9]*.jpg的格式,有兴趣的可以自己把大图的名字也爬下来设置为图片名称
    4.高清原图需要登录,留坑

    在这里插入图片描述

    展开全文
  • 爬虫小程序 - 爬取王者荣耀全皮肤

    万次阅读 多人点赞 2019-09-04 21:26:47
    王者荣耀全皮肤图片爬取
  • CSDN个人博客列表爬取

    2020-02-05 00:04:44
    爬取完简书上的博客列表之后,又尝试爬取了CSDN个人主页的文章列表,程序实现的技术路线依旧是requesets+xpath。 爬取的文章信息主要包括:文章标题、文章类型、文章链接、文章摘要、发布时间、阅读数、评论数。
  • 爬取图片

    2020-07-18 14:37:52
    用爬虫爬取小姐姐的图片 用的库 re #正则表达式 requests #url请求 time #时间 os #用于创建文件夹,保存图片 ##准备工作 1.首先访问该链接 https://www.vmgirls.com/ 2.随便点击一个进入查看详情 ...
  • 不知道大家平常喜不喜欢待在宿舍一个人看电影? 作为一个高龄屌丝,电影对我来说是必不可少的。平常无聊时自己一个人待在宿舍看看电影,看看书。 (人闲下来就会胡思乱想,不能让寂寞侵蚀自己的内心) ...
  • 爬取需要登录的网站

    2019-04-29 08:09:37
    爬取需要登录信息的网站 不知道算不算违规,不过还是记录一下,属于比较有用的小技巧。有的网站需要登录,才能查看其里面的东西。有时候如果只是文字的东西,想要分享出去。比如说极客时间的专栏。 那就爬取内容保存...
  • python网页爬取多页爬取

    千次阅读 2019-09-20 20:47:54
    0.从新闻url获取点击次数... newsUrl newsId(re.search()) clickUrl(str.format()) requests.get(clickUrl) re.search()/.split() str.lstrip(),str.rstrip() int 整理成函数 获取新闻发布时间及类型转换也整理成函数 ...
  • 爬取一个网站

    千次阅读 2019-06-16 20:36:10
    如果一个页面有10个链接,网站上有5个页面深度(中等规模网站的主流深度),如果要采集整个网站,一共需要采集的网页数量就是10^5,即100000个页面,因为很少有网站会涉及到这么多的网页,因为有很大一部分是因为网页...
  • 爬取网站视频

    千次阅读 2019-07-01 15:56:00
    '''爬取校花网视频 1.请求url http://www.xiaohuar.com/v/ 2.请求方式 GET 3.请求头信息 User-Agent:用户代理'''# 爬虫三部曲# 1.发送请求import requestsimport timedef get_page(url): response = requests.get...
  • Python爬虫实战之爬取网站全部图片(一)

    万次阅读 多人点赞 2018-09-02 12:28:21
    Python爬虫实战之爬取网站全部图片(二) 传送门: https://blog.csdn.net/qq_33958297/article/details/89388556 爬取网址: http://www.meizitu.com/a/more_1.html 爬取地址:...
  • 爬虫|菜鸟的学习之路——爬取一本小说

    万次阅读 多人点赞 2018-07-11 00:07:28
    前言:本次爬取的是全书网的某一本小说并以.TXT格式下载到本地。工具:python3 和 pycharmPython库:urllib.request 和 re注意:python是用3以上的版本,库可以在Windows命令提示符里输入pip install+库名第一步:1....
  • web爬虫学习(四)——手机APP爬取

    万次阅读 2018-06-29 00:30:29
    笔者是一个痴迷于挖掘数据中的价值的学习人,希望在平日的工作学习中,挖掘数据的价值,找寻数据的秘密,笔者认为,数据的价值不仅仅只体现在企业中,个人也可以体会到数据的魅力,用技术力量探索行为密码,让大数据...
  • python爬取知网论文信息

    万次阅读 多人点赞 2018-03-27 09:28:45
    背景 老师让我爬图书馆所有关于地学的资料,并用深度学习分析。 当时让我爬图书馆,内心是极度崩溃的!!!我还是个孩子啊!!!...很幸运的找到了一个大佬的代码来自己改改改!...接下来就是我自己嚯嚯嚯改的很小白的了...
  • # -*- coding: utf-8 -*- ...2、我是利用selenium自动化测试工具进行爬取的,所以要再安装Selenium库,pip install selenium 3、ChromeDriver环境配置,先知道安装的Chrome浏览器的版本号,然后去https...
  • 使用python爬虫技术爬取知网的标题和摘要信息。使用了多线程,爬取的数据存储在mysql数据库中。
  • python爬虫——使用selenium爬取知网文献相关信息

    万次阅读 热门讨论 2019-04-11 22:58:11
    2. 知网的反爬虫手段很强,反正我爬取pc端的时候,用selenium爬取获取不到源代码,真是气人,后来换成手机端就可以获取了,爬取手机端的操作如下。 3. 首先进入知网后,选择开发工具,建议放在右边,之后再点击图中...
  • python爬取知网

    万次阅读 2017-12-27 13:40:27
    最近在练习写爬虫的时候,真巧同学的女朋友有需求,大概是爬取知网内的几千个主题的数据,每一个主题的条数记录有几条的到几千条的不等,总来的来说也算是个上万数量级的爬虫了,分析了下知网,发现使用专业检索,...

空空如也

1 2 3 4 5 ... 20
收藏数 166,828
精华内容 66,731
关键字:

爬取