Python学习日志——通过互联网实现采集功能

一、正则表达式和BeautifulSoup

1.利用正则表达式查找所需内容

通过正则表达式与BeautifulSoup库的结合使用,可以使查找所需内容的工作更加灵活。

bsObj.findAll("img",{"src":re.compile("\.\.\/img\/difts\/img.*\.jpg")})

#查找条件为:   ../img/difts/ img.*.jpg
../img/difts/(到此为目录)      img.*(所有图片都以img开头,之后为任意字符)  .jpg(都以jpg结尾)

例:查找赶集网宠物网页中,带有“?”的句子

import urllib.request as ur
from bs4 import BeautifulSoup
import re
html = ur.urlopen("http://bj.ganji.com/chongwu/")
bsObj = BeautifulSoup(html.read(),"html.parser")
links = bsObj.findAll("a",{"title":re.compile("?$")})
for link in links:
    if "title" in link.attrs:
        print(link.attrs["title"])

结果:
被狗狗咬了如何处理?
如何给萨摩狗狗买玩具?
萨摩耶犬好养吗?
雪纳瑞好养吗?

2.利用attrs获取属性

对于一个标签,我们可以利用attrs获取它的全部属性,也可以获取单个属性。获取全部属性时返回字典

例:查找标签属性个数为2的所有标签

import urllib.request as ur
from bs4 import BeautifulSoup
import re
html = ur.urlopen("http://bj.ganji.com/chongwu/")
bsObj = BeautifulSoup(html.read(),"html.parser")
links = bsObj.findAll("a",{"title":re.compile("?$")})
for link in links:
    if "title" in link.attrs:
        print(link.attrs)
        print(link.attrs["title"])


结果:
{'href': 'http://www.ganji.com/mao/11012515-28127.htm', 'target': '_blank', 'title': '教您如何挑选猫猫?'}
教您如何挑选猫猫?
{'href': 'http://www.ganji.com/mao/11012515-28130.htm', 'target': '_blank', 'title': '被猫抓了如何处理?'}
被猫抓了如何处理?
{'title': '如何给萨摩狗狗买玩具?', 'target': '_blank', 'href': 'http://www.ganji.com/zhishi/news_4403.htm'}
如何给萨摩狗狗买玩具?
{'title': '萨摩耶犬好养吗?', 'target': '_blank', 'href': 'http://www.ganji.com/zhishi/news_4410.htm'}
萨摩耶犬好养吗?

2.Lambda表达式

Lambda表达式可以将函数作为参数进行查找

import urllib.request as ur
from bs4 import BeautifulSoup
import re
html = ur.urlopen("http://bj.ganji.com/chongwu/")
bsObj = BeautifulSoup(html.read(),"html.parser")
links = bsObj.findAll(lambda a:len(a.attrs)==2)
for link in links:
        print(link.attrs)

结果:
{'http-equiv': 'Content-Type', 'content': 'text/html; charset=utf-8'}
{'name': 'renderer', 'content': 'webkit'}
{'name': 'keywords', 'content': '北京宠物网,北京宠物店,北京宠物市场,北京网上宠物市场'}
{'name': 'description', 'content': '赶集网北京宠物网是专业的北京网上宠物交易市场,您可以免费查看发布北京宠物买卖、宠物赠送、宠物领养、宠物交友、宠物店、宠物用品批发等信息。'}
{'name': 'mobile-agent', 'content': 'format=html5; url=http://3g.ganji.com/bj_pet/'}
{'name': 'mobile-agent', 'content': 'format=xhtml; url=http://wap.ganji.com/bj/pet/'}
{'name': 'location', 'content': 'province=北京;city=北京'}
{'src': '//sta.ganjistatic1.com/public/js/util/ganji/ganji.__1562407200__.js', 'type': 'text/javascript'}
{'data-widget': 'app/ms_v2/common/base_page.js#topNav', 'class': ['top-nav', 'fl']}
{'class': ['ganji-dingdong'], 'data-widget': 'app/ms_v2/common/base_page.js#hoverWidget'}
{'class': ['column', 'ganji-dingdong'], 'data-widget': 'app/ms_v2/common/base_page.js#hoverWidget'}
{'data-widget': 'app/ms_v2/common/base_page.js#hoverWidget', 'class': ['top-nav', 'fl']}
{'class': ['top-nav-btn', 'clearfix', 'js-btn'], 'href': 'http://bj.ganji.com/tuiguang/'}
{'gjalog': '/self_service/trace@source=self_promotion_post_index_header@city_id=12@cat=chongwu@atype=click', 'href': 'http://bj.ganji.com/tuiguang/zhaopin/bangbang/'}
{'gjalog': '/self_service/trace@source=self_promotion_post_index_header@city_id=12@cat=chongwu@atype=click', 'href': 'http://bj.ganji.com/tuiguang/fang/bangbang/'}
{'gjalog': '/self_service/trace@source=self_promotion_post_index_header@city_id=12@cat=chongwu@atype=click', 'href': 'http://bj.ganji.com/tuiguang/fuwu/bangbang/'}
{'gjalog': '/self_service/trace@source=self_promotion_post_index_header@city_id=12@cat=chongwu@atype=click', 'href': 'http://bj.ganji.com/tuiguang/che/bangbang/'}
{'gjalog': '/self_service/trace@source=self_promotion_post_index_header@city_id=12@cat=chongwu@atype=click', 'href': 'http://bj.ganji.com/tuiguang/wu/bangbang/'}
{'gjalog': '/self_service/trace@source=self_promotion_post_index_header@city_id=12@cat=chongwu@atype=click', 'href': 'http://bj.ganji.com/tuiguang/chongwu/bangbang/'}
{'class': ['fl', 'reg-login'], 'data-widget': 'app/ms_v2/common/base_page.js#userinfoWidget'}
{'class': ['h-search'], 'data-widget': 'app/ms_v2/common/list_page.js#fixSearchBar'}
{'class': ['logo-2013'], 'href': '/'}
{'class': ['sear-menu0-con'], 'data-role': 'options'}
{'href': '###', 'title': '宠物'}
{'href': '###', 'title': '所有分类'}
{'id': 'wrapper', 'class': ['pet-categroy', 'clearfix']}
{'href': '/chongwupeizhong/3611518915x.htm', 'target': '_blank'}
{'href': '/chongwupeizhong/3603555111x.htm', 'target': '_blank'}
{'target': '_self', 'href': '#floor1'}
{'target': '_self', 'href': '#floor2'}
{'target': '_self', 'href': '#floor3'}
{'target': '_self', 'href': '#floor4'}
{'target': '_self', 'href': '#floor5'}
{'target': '_self', 'href': '#floor6'}
{'target': '_self', 'href': '#floor7'}
{'name': 'floor1', 'id': 'floor1'}
{'href': '/gou/', 'target': '_blank'}
{'href': '/chongwushipin/', 'target': '_blank'}
{'href': '/chongwurichangyongju/', 'target': '_blank'}
{'href': '/chongwupeizhong/', 'target': '_blank'}
{'href': '/chongwufuwu/', 'target': '_blank'}
{'href': '/chongwujiyang/', 'target': '_blank'}
{'href': '/chongwumeirong/', 'target': '_blank'}
{'href': '/chongwuyiyuan/', 'target': '_blank'}
{'href': '/taidixiong/', 'target': '_blank'}
{'href': '/zangao/', 'target': '_blank'}
{'href': '/jinmao/', 'target': '_blank'}
{'href': '/hashiqi/', 'target': '_blank'}
{'href': '/deguomuyangquan/', 'target': '_blank'}
{'href': '/bomeiquan/', 'target': '_blank'}
{'href': '/samoquan/', 'target': '_blank'}
{'href': '/abuladuo/', 'target': '_blank'}
{'href': '/gou/', 'target': '_blank'}
{'name': 'floor2', 'id': 'floor2'}
{'href': '/mao/', 'target': '_blank'}
{'href': '/maoliang/', 'target': '_blank'}
{'href': '/maoyongpin/', 'target': '_blank'}
{'href': '/chongwupeizhong/', 'target': '_blank'}
{'href': '/chongwufuwu/', 'target': '_blank'}
{'href': '/chongwujiyang/', 'target': '_blank'}
{'href': '/chongwumeirong/', 'target': '_blank'}
{'href': '/chongwuyiyuan/', 'target': '_blank'}
{'href': '/mao/', 'target': '_blank'}
{'name': 'floor3', 'id': 'floor3'}
{'href': '/guanshangyu/', 'target': '_blank'}
{'href': '/yusiliao/', 'target': '_blank'}
{'href': '/boliyugang/', 'target': '_blank'}
{'href': '/shuizufuwu/', 'target': '_blank'}
{'href': '/guanshangyu/', 'target': '_blank'}
{'name': 'floor4', 'id': 'floor4'}
{'href': '/yingwu/', 'target': '_blank'}
{'href': '/bage/', 'target': '_blank'}
{'href': '/gezi/', 'target': '_blank'}
{'href': '/niao/', 'target': '_blank'}
{'name': 'floor5', 'id': 'floor5'}
{'href': '/qitaxiaochong/', 'target': '_blank'}
{'href': '/longmao/', 'target': '_blank'}
{'href': '/gui/', 'target': '_blank'}
{'href': '/cangshu/', 'target': '_blank'}
{'href': '/chongwuzhu/', 'target': '_blank'}
{'href': '/qitaxiaochong/', 'target': '_blank'}
{'name': 'floor6', 'id': 'floor6'}
{'href': '/chongwushipin/', 'target': '_blank'}
{'href': '/chongwurichangyongju/', 'target': '_blank'}
{'href': '/maoliang/', 'target': '_blank'}
{'href': '/maoyongpin/', 'target': '_blank'}
{'href': '/boliyugang/', 'target': '_blank'}
{'href': '/chongwuwanju/', 'target': '_blank'}
{'href': '/chongwuyongpin/', 'target': '_blank'}
{'href': '/chongwuyiyuan/', 'target': '_blank'}
{'href': '/chongwujiyang/', 'target': '_blank'}
{'href': '/chongwumeirong/', 'target': '_blank'}
{'href': '/shuizufuwu/', 'target': '_blank'}
{'href': '/chongwufuwu/', 'target': '_blank'}
{'name': 'floor7', 'id': 'floor7'}
{'href': '/chongwujiuzhu/', 'target': '_blank'}
{'href': '/jiayangzengsong/', 'target': '_blank'}
{'href': '/qiuyangchongwu/', 'target': '_blank'}
{'href': '/free/', 'target': '_blank'}
{'class': ['backtotop', ''], 'data-widget': 'app/ms_v2/common/base_page.js#sideFloatWidget'}
{'target': '_blank', 'href': '/chongwuliebiao.htm'}
{'href': 'http://sh.ganji.com/chongwu/', 'target': '_blank'}
{'href': 'http://longyu.cc/', 'target': '_blank'}
{'href': 'http://www.apetdog.com/', 'target': '_blank'}
{'href': 'http://www.epet.com/', 'target': '_blank'}
{'href': 'http://bj.58.com/chongwu/', 'target': '_blank'}
{'target': '_blank', 'href': 'http://bj.ganji.com/quxiandaohang/'}
{'target': '_blank', 'href': 'http://wap.ganji.com/bj/pet/'}
{'target': '_blank', 'href': 'http://3g.ganji.com/bj_pet/'}

二、遍历单个域名

爬虫的本质就是一种递归方式。为了找到URL链接,它们必须首先获取网页内容,检查这个页面的内容,在寻找另外一个URL,然后后获取URL对应的网页内容,不断循环这一过程。根据“维基百科六度分隔理论”的查找方法,从张云雷百度词条页面通过最少的点击链接,找到岳云鹏的词条页面

import urllib.request as ur
from bs4 import BeautifulSoup
html = ur.urlopen("https://baike.baidu.com/item/%E5%BC%A0%E4%BA%91%E9%9B%B7/17149")
bsObj = BeautifulSoup(html,"html.parser")
for link in bsObj.findAll("a"):
    if 'href' in link.attrs:
        print(link.attrs['href'])

你会发现结果为一系列的链接,其中有些是我们需要的,有些不是我们需要的。其实百度百科的每个页面都充满了侧边栏、页眉、以及连接到分类页面、对话页面和其他不包含词条的页面的链接。经过对采集页面的分析,发现那些指向词条页面(不是指向其他内容页面)的链接,会发现他们有两个个特点:

  • 他们都在dd标签中

  • class属性值都是basicInfo-item value

利用这些,我们可以稍微调整一下代码:

import urllib.request as ur
from bs4 import BeautifulSoup
html = ur.urlopen("https://baike.baidu.com/item/%E5%BC%A0%E4%BA%91%E9%9B%B7/17149")
bsObj = BeautifulSoup(html,"html.parser")
for link in bsObj.findAll("dd",{"class":"basicInfo-item value"}):
    url = link.find("a")
    if url != None:
        print(url.attrs["href"])

 在实际应用中,我们需要让代码符合以下要求:

 1.一个函数getLinks,可以用百度百科链接+分页面路径(https://baike.baidu.com + /item/%E5%BC%A0%E4%BA%91%E9%9B%B7/17149)形式的URL链接作为参数,然后以同样的形式返回一个列表,其中包含所有的词条URL链接。

 2. 一个主函数,以某个起始词条为参数调用getLinks,再从返回的URL列表里随机选择一个词条链接,再重复调用getLinks,直到我们主动停止,或者在新的界面上没有词条链接了,程序才停止执行。

import urllib.request as ur
from bs4 import BeautifulSoup
import datetime  #导入随机数生成器
import random

random.seed(datetime.datetime.now())  #生成随机数
def getLinks(url):
    html = ur.urlopen(url)
    bsObj = BeautifulSoup(html,"html.parser")
    links = []
    for link in bsObj.findAll("dd",{"class":"basicInfo-item value"}):
        url = link.find("a")
        if url != None:
            links.append(url.attrs["href"])
    return links

url = "https://baike.baidu.com/item/%E5%BC%A0%E4%BA%91%E9%9B%B7/17149"
ls = getLinks(url)
while len(ls)>0:
    newArticle = "https://baike.baidu.com"+ls[random.randint(0,len(ls)-1)]
    print(newArticle)
    ls = getLinks(newArticle)

程序中用系统当前时间生成一个随机数生成器 ,保证在每次运行的时候,百度百科词条的选择都是一个全新的随机路径。

三、采集整个网站

一个常用的网站采集方法就是从顶级页面开始,然后搜索页面上的所有链接,形成列表。再去采集这些链接的每一个页面,然后把在每个页面上找到的链接形成新的列表,重复执行下一轮采集。 但在采集过程中,不可避免的会将一些网页重复采集,因此需要对链接进行去重处理。

import urllib.request as ur
from bs4 import BeautifulSoup
import re

pages = set()
def getLinks(url):
    global pages
    html = ur.urlopen("https://baike.baidu.com"+url)
    bsObj = BeautifulSoup(html,"html.parser")
    print(bsObj.title.get_text())
    for dd in bsObj.findAll("dd",{"class":"basicInfo-item value"}):
        alinks = dd.findAll("a")
        for alink in alinks:
            if "href" in alink.attrs:
                if alink.attrs["href"] not in pages:
                     #我们遇到了新页面
                    newPage = alink.attrs["href"]
                    print(newPage)
                    pages.add(newPage)
                    getLinks(newPage)

url = "/item/%E5%BC%A0%E4%BA%91%E9%9B%B7/17149"
getLinks(url)

注:如果递归运行的次数非常多,前面的递归程序就很可能崩溃。python默认的递归限制是1000次。因为百度百科网络链接体量极大,所以这个程序达到递归限制后就会停止。解决方法为设置一个较大的递归计数器,或用其他手段不让它停止。

四、通过互联网采集

当爬取整个互联网时,需要关注外链接的存在,外链接的特点一般是以http,https和www开头。但是跟随外链接跳转之前,需要注意一下问题:

  • 外链接可能会链接到一些宗教或黄色网站,需要进行排除和筛选

  • 明确要收集哪些数据,避免获取大量无用数据

  • 当爬取到某个网站的时候,是直接链接到一个新的网站还是在当前网站暂停

  • 如果引起了某网站网关的怀疑,如何避免法律责任。

import urllib.request as ur
from bs4 import BeautifulSoup
import re

pages = set()
#获取内链接
def getLinks(url):
    global pages
    html = ur.urlopen("https://baike.baidu.com"+url)
    bsObj = BeautifulSoup(html,"html.parser")
    for dd in bsObj.findAll("dd",{"class":"basicInfo-item value"}):
        alinks = dd.findAll("a")
        for alink in alinks:
            if "href" in alink.attrs:
                if alink.attrs["href"] not in pages:
                     #我们遇到了新页面
                    newPage = alink.attrs["href"]
                    print(newPage)
                    pages.add(newPage)
                    getLinks(newPage)
pages0 = set()
def getLinks0(url):
    global pages0
    html = ur.urlopen("https://baike.baidu.com" + url)
    bsObj = BeautifulSoup(html, "html.parser")
    for link in bsObj.findAll("a", href = re.compile("^(http|https|www)")):
        if link.attrs["href"] not in pages0:
            newPage = link.attrs["href"]
            print(newPage)
            pages0.add(newPage)
            getLinks0(newPage)       
url = "/item/%E5%BC%A0%E4%BA%91%E9%9B%B7/17149"
getLinks(url)
getLinks0(url)

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值