zoukankan      html  css  js  c++  java
  • 使用beautifulsoup与requests爬取数据

    1、安装需要的库

    bs4 beautifulSoup  requests lxml
    如果使用mongodb存取数据,安装一下pymongo插件

    2、常见问题

    1> lxml安装问题

    如果遇到lxml无法安装问题,参考知乎上的答案:

    首先,安装wheel,命令行运行:pip install wheel
    其次,在这里下载对应的.whl文件,注意别改文件名!http://www.lfd.uci.edu/~gohlke/pythonlibs/#lxml
    Ctrl + F,输入lxml,找到下面这段Lxml,
    Lxml, a binding for the libxml2 and libxslt libraries.
    lxml‑3.7.1‑cp27‑cp27m‑win32.whl

    lxml‑3.7.1‑cp27‑cp27m‑win_amd64.whl

    lxml‑3.7.1‑cp34‑cp34m‑win32.whl

    lxml‑3.7.1‑cp34‑cp34m‑win_amd64.whl

    lxml‑3.7.1‑cp35‑cp35m‑win32.whl

    lxml‑3.7.1‑cp35‑cp35m‑win_amd64.whl

    lxml‑3.7.1‑cp36‑cp36m‑win32.whl

    lxml‑3.7.1‑cp36‑cp36m‑win_amd64.whl
    cp后面是Python的版本号,27表示2.7,根据你的Python版本选择下载。
    之后, 进入.whl所在的文件夹,执行命令即可完成安装pip install 带后缀的完整文件名

    2> pip问题
    如果提示 'pip' 不是内部或外部命令,也不是可运行的程序。

    多是因为环境变量没有设置好。需要设置两个,一些常用的命令在Scripts文件夹下面

    以下两个改为自己计算机的路径

    C:FilesPythonPython36
    C:FilesPythonPython36Scripts

    3、mongodb

    如何安装mongodb参见https://docs.mongodb.com/manual/tutorial/install-mongodb-on-ubuntu/

    服务启动与停止

    sudo service mongod start
    sudo service mongod stop
    sudo service mongod restart

    配置文件位于 /etc/mongod.conf,默认端口 27017 ,修改可以在配置文件中修改

    # network interfaces
    net:
      port: 27017
    #  bindIp: 127.0.0.1

    此外,默认绑定了ip地址127.0.0.1,需要将此句注释掉,否则远程无法访问

    4、参考代码

    import requests
    from bs4 import BeautifulSoup
    import time
    import pymongo
    import random
    from multiprocessing import Pool
    # 导入多个对象或者函数用逗号分开
    # from test_parsing import get_items,url_list
    
    # mongodb客户端
    client = pymongo.MongoClient('192.168.1.101',27017)
    # 数据库
    test = client['testdata']
    # 各种表
    tb = test['testtable']
    mb= test['itemtable']
    detail= test['detailtable']
    
    headers  = {
    User-Agent:
        'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/55.0.2883.87 Safari/537.36',
        'Connection':'keep-alive'
    }
    
    
    proxy_list = [
        'http://118.79.27.123:8081',
        'http://113.108.253.195:9797',
        ]
    
    # 随机获取代理ip
    proxy_ip = random.choice(proxy_list) 
    proxies = {'http': proxy_ip}
    
    # 简单用例
    def get_pages_within(pagenums):
        for page_num in range(1,pagenums+1):
            # 请求
            wb_data = requests.get('http://urldata/test/pn{}/'.format(page_num))
            # 包装一个对象
            soup = BeautifulSoup(wb_data.text,'lxml')
            # 使用select方法,参数为样式选择器,div.price_li > span 标识逐层级关系,div.price_li span 只是简单的包含关系        
            numbers = soup.select('div.number')
            prices = soup.select('span.price')
            
            links = soup.select('a.t')
    
            for number, price, link in zip(numbers,prices,links):             
                if int(price.get_text()) > 500:
                    print(number,price)
                data = {
                    'title':number.get_text(),
                    'price':price.get_text(),
                    'link' :link.get('href')
                }
                tb.insert_one(data)
            print('finished')
    
    # 复杂点的
    def get_links_from(source, pages, flag='c'):
        list_view = '{}{}{}/'.format(source, str(flag), str(pages))
        # 带参数
        wb_data = requests.get(list_view,headers=headers,proxies=proxies)
        soup = BeautifulSoup(wb_data.text, 'lxml')
        if soup.find('ul', 'pageLink'):
            for link in soup.select('.fenlei dt a'):
                item_link = link.get('href')
                mb.insert_one({'url': item_link})
                print(item_link)
                
        else:
            pass
    
    
    def get_detail_from(url,data=None):
        wb_data = requests.get(url,headers=headers)
        time.sleep(1)
        # flag = 'flagnumber' in soup.find('script', type="text/javascript").get('src').split('/')
        # if flag: 
        if wb_data.status_code == 404:    
            pass
        else:
            soup = BeautifulSoup(wb_data.text, 'lxml')
            data = {
                'title':soup.title.text.strip(),
                'price':soup.select('div.price_li > span > i')[0].text.strip(),
                'time':soup.select('.pubtime')[0].text.strip().split('/')[0],
                'area':list(map(lambda x:x.text,soup.select('ul.area-infor > li > a'))),
                'cates':list(soup.select('div.cates > span > i')[0].stripped_strings),
                'url':url
            }       
            detail.insert_one(data)
    
    source_list = '''
    http://test.com/books/
    http://test.com/pictures/
    '''
    
    # 读取数据
    # $lt/$lte/$gt/$gte/$ne,依次等价于</<=/>/>=/!=。(l表示less g表示greater e表示equal n表示not  )
    for item in detail.find({'price': {'$lt': 100}}):
        print(item)
        
    for i in detail.find():
        if i['price'] >= 500:
            print(i)
    
    if __name__ == '__main__':
        # 使用多进程
        pool = Pool()
        # pool = Pool(processes=2)
        if source_list is not None:
            pool.map(get_links_from,source_list.split())
        
        pool.close()
        pool.join()

    一般使用谷歌浏览器对要爬取的元素进行检查,在这一方面,好用一些,右键,选择Copy selector,获取到例如:div.cates > span > i,作为select函数的参数即可。

     也可以自己写,在浏览器的检查元素页面上,ctrl + F 出现查找框,写入要使用的样式选择器,看看是否准确即可 。

    例子:div.price_li > span 标识逐层级关系,div.price_li span 只是简单的包含关系

     

     5、参考文档

    http://beautifulsoup.readthedocs.io/zh_CN/latest/

    http://www.python-requests.org/en/master/

  • 相关阅读:
    关于键盘事件对象code值
    解决父元素定位后宽度不随着子元素增大而增大的问题
    绝对定位后元素的宽高如果用百分比表示的计算方法
    4.7做作业时发现,内联元素设置宽高背景以后正常不显示,但是设置了position:absolute;以后就可以显示了。起到了和display:block;一样的效果。然后查了一下知道了。
    react-native中显示本地照片或视频
    用js实现div元素的拖拽、
    TCP协议浅谈
    TCP的三次握手和四次挥手
    TCP协议
    关于this指向的一点小分享
  • 原文地址:https://www.cnblogs.com/learn21cn/p/6243537.html
Copyright © 2011-2022 走看看