TomorrowLi's Blog


  • 首页

  • 关于

  • 标签

  • 分类

  • 归档

  • 搜索

用正则表达式来爬取某论坛的邮箱地址

发表于 2021-07-18 | 分类于 爬虫
字数统计: 101 | 阅读时长 ≈ 1

代码演示:

import re

import requests
def fand_email(url,counts):
    data=requests.get(url)
    content=data.text
    pattern = r'[0-9a-zA-Z._]+@[0-9a-zA-Z._]+\.[0-9a-zA-Z._]+'
    p = re.compile(pattern)
    m = p.findall(content)
    with open('emal.txt','a+') as f:
        for i in m:
            f.write(i+'\n')
            print(i)
            counts= counts+1
    return counts
def main():
    counts=0
    numbers=0
    for i in range(1,32):
        url='http://tieba.baidu.com/p/2314539885?pn=%s'% i
        number=fand_email(url,counts)
        numbers=numbers+number
    print(numbers)
if __name__ == '__main__':
    main()

用selenium自动爬取天眼查上的公司信息

发表于 2021-07-18 | 分类于 爬虫
字数统计: 644 | 阅读时长 ≈ 4

Quict Start

1、需要的库

re、selenium、pymysql

2、程序前的准备

首先在自己的python路径下放入 chromedriver.exe 选择自己浏览器合适的版本下载

代码展示

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
import re
import MySQLdb
host='localhost'#主机名
user='root'#数据库的用户名
passwd=''#数据库的密码
db='test'#数据库的名字
conn=MySQLdb.connect(host,user,passwd,db,charset='utf8')
cursor = conn.cursor()
boser=webdriver.Chrome()
boser.maximize_window()
wait=WebDriverWait(boser , 10)
def getlogin():
    boser.get('https://www.tianyancha.com/login')
    user = wait.until(
        EC.presence_of_element_located((By.CSS_SELECTOR, "#web-content > div > div > div > div.position-rel.container.company_container > div > div.in-block.vertical-top.float-right.right_content.mt50.mr5.mb5 > div.module.module1.module2.loginmodule.collapse.in > div.modulein.modulein1.mobile_box.pl30.pr30.f14.collapse.in > div.pb30.position-rel > input"))
    )
    password=wait.until(
        EC.presence_of_element_located((By.CSS_SELECTOR, '#web-content > div > div > div > div.position-rel.container.company_container > div > div.in-block.vertical-top.float-right.right_content.mt50.mr5.mb5 > div.module.module1.module2.loginmodule.collapse.in > div.modulein.modulein1.mobile_box.pl30.pr30.f14.collapse.in > div.pb40.position-rel > input'))
    )
    submit = wait.until(
        EC.element_to_be_clickable((By.CSS_SELECTOR , '#web-content > div > div > div > div.position-rel.container.company_container > div > div.in-block.vertical-top.float-right.right_content.mt50.mr5.mb5 > div.module.module1.module2.loginmodule.collapse.in > div.modulein.modulein1.mobile_box.pl30.pr30.f14.collapse.in > div.c-white.b-c9.pt8.f18.text-center.login_btn'))
    )
    user.send_keys('用户名')
    password.send_keys('密码')
    submit.click()
    getSearch()
def getSearch():
    user = wait.until(
        EC.presence_of_element_located((By.CSS_SELECTOR , "#home-main-search"))
    )
    submit = wait.until(
        EC.element_to_be_clickable((By.CSS_SELECTOR ,
                                    '#web-content > div > div.mainV3_tab1_enter.position-rel > div.mainv2_tab1.position-rel > div > div.main-tab-outer > div:nth-child(2) > div > div:nth-child(1) > div.input-group.inputV2 > div > span'))
    )
    key='佛山市顺德区'
    user.send_keys(key)
    submit.click()
    html=boser.page_source
    geturl(html)
    getUrlNext()
def getUrlNext():
    for i in range(2,5):
        boser.get(r'https://www.tianyancha.com/search/p%s?key=佛山市顺德区'% i)
        html=boser.page_source
        geturl(html)
def geturl(html):
    try:
        reg=r'<a href=".*?" target="_blank" tyc-event-click="" tyc-event-ch="CompanySearch.Company" style="word-break: break-all;font-weight: 600;" class="query_name sv-search-company f18 in-block vertical-middle"><span>(.*?)</span></a>'
        names=re.findall(reg,html,re.S)
        reg=r'<a title=".*?" class="legalPersonName hover_underline" target="_blank" href=".*?">(.*?)</a>'
        daibiao=re.findall(reg,html,re.S)
        reg=r'<div class="title overflow-width" style="border-right: none">.*?<span title=".*?">(.*?)</span></div>'
        days = re.findall(reg,html,re.S)
        reg=r'<span class="sec-c3">联系电话:</span><span class="overflow-width over-hide vertical-bottom in-block" style="max-width:500px;">(.*?)</span>'
        phones = re.findall(reg , html , re.S)
        reg=r'<div class="add"><span class="sec-c3">.*?</span><span>:</span><span class="overflow-width over-hide vertical-bottom in-block" style="max-width:500px;">(.*?)</span>'
        location=re.findall(reg,html,re.S)
        for i in range(20):
            data={
                'name':names[i].replace('<em>','').replace('</em>',''),
                'daibiao':daibiao[i],
                'day':days[i].replace('<em>','').replace('</em>',''),
                'phone':phones[i].replace('<em>','').replace('</em>',''),
                'location': location[i].replace('<em>', '').replace('</em>','')
            }
            print(data)
            cursor.execute("insert into tianyancha(name,daibiao,day,phone,location) values('{}','{}','{}','{}','{}')".format(data['name'],data['daibiao'],data['day'],data['phone'],data['location']))
            print(data['daibiao'],'成功存入数据库')
            conn.commit()

    except:
        return None
def main():
    getlogin()

if __name__ == '__main__':
    main()

结果展示

image

Spring的IOC

发表于 2021-07-18 | 分类于 spring
字数统计: 757 | 阅读时长 ≈ 3

1、Spring的IOC

1.1、实例化 Bean 的三种方式

第一种方式:使用默认无参构造函数(最为常用)

    <!--在默认情况下:
    它会根据默认无参构造函数来创建类对象。如果 bean 中没有默认无参构造函数,将会创建失败。
    <bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl"/>
阅读全文 »

Spring的AOP

发表于 2021-07-18 | 分类于 spring
字数统计: 125 | 阅读时长 ≈ 1

1、springAOP

作用:  
    在程序运行期间,不修改源码对已有方法进行增强。 
优势:  
    减少重复代码     
    提高开发效率    
    维护方便 

1.1 基于接口的动态代理

提供者:JDK 官方的 Proxy 类。  

要求:被代理类最少实现一个接口。 

1,2 基于子类的动态代理

提供者:第三方的 CGLib,如果报 asmxxxx 异常,需要导入 asm.jar。

要求:被代理类不能用 final 修饰的类(最终类)。 

爬取淘宝美食信息并存储到数据库中

发表于 2021-07-18 | 分类于 爬虫
字数统计: 515 | 阅读时长 ≈ 3

代码演示:

import re

import MySQLdb
from selenium import webdriver
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from pyquery import PyQuery as pq
broser=webdriver.Chrome()

wait=WebDriverWait(broser, 10)
def search(table):
    try:
        broser.get('https://www.taobao.com')
        inputs = wait.until(
            EC.presence_of_element_located((By.CSS_SELECTOR, "#q"))
        )
        submit = wait.until(
            EC.element_to_be_clickable((By.CSS_SELECTOR, '#J_TSearchForm > div.search-button > button'))
        )
        inputs.send_keys('美食')
        submit.click()
        total = wait.until(
            EC.element_to_be_clickable((By.CSS_SELECTOR,'#mainsrp-pager > div > div > div > div.total'))
        )
        get_product(table)
        return total.text
    except TimeoutException:
        return search(table)
def next_page(page_number,table):
    try:
        inputs = wait.until(
            EC.presence_of_element_located((By.CSS_SELECTOR, "#mainsrp-pager > div > div > div > div.form > input"))
        )
        submit = wait.until(
            EC.element_to_be_clickable((By.CSS_SELECTOR, "#mainsrp-pager > div > div > div > div.form > span.btn.J_Submit"))
        )
        inputs.clear()
        inputs.send_keys(page_number)
        submit.click()
        wait.until(
            EC.text_to_be_present_in_element((By.CSS_SELECTOR, "#mainsrp-pager > div > div > div > ul > li.item.active > span"),str(page_number))
        )
        get_product(table)
    except TimeoutException:
        next_page(page_number,table)
def get_product(table):
    wait.until(EC.presence_of_element_located((By.CSS_SELECTOR,'#mainsrp-itemlist .items .item')))
    html=broser.page_source
    doc=pq(html)
    items=doc('#mainsrp-itemlist .items .item').items()
    for item in items:
        product={
            'image':item.find('.pic .img').attr('src'),
            'price':item.find('.price').text().replace('\n',''),
            'deal':item.find('.deal-cnt').text()[:-3],
            'title':item.find('.title').text().replace('\n',''),
            'shop':item.find('.shop').text(),
            'location':item.find('.location').text()
        }
        print(product)
        inserttable(table, product['image'], product['price'], product['deal'], product['title'],product['shop'],product['location'])
#连接数据库 mysql
def connectDB():
        host="localhost"
        dbName="test"
        user="root"
        password=""
        #此处添加charset='utf8'是为了在数据库中显示中文,此编码必须与数据库的编码一致
        db=MySQLdb.connect(host,user,password,dbName,charset='utf8')
        return db
        cursorDB=db.cursor()
        return cursorDB

#创建表,SQL语言。CREATE TABLE IF NOT EXISTS 表示:表createTableName不存在时就创建
def creatTable(createTableName):
    createTableSql="CREATE TABLE IF NOT EXISTS "+ createTableName+"(image VARCHAR(255),price VARCHAR(255),deal  VARCHAR(255),title VARCHAR(255),shop VARCHAR(255),location VARCHAR(255))"
    DB_create=connectDB()
    print('链接数据库成功')
    cursor_create=DB_create.cursor()
    cursor_create.execute(createTableSql)
    DB_create.close()
    print('creat table '+createTableName+' successfully')
    return createTableName
#数据插入表中
def inserttable(insertTable,insertimages,insertprice,insertdeal,inserttitle,insertshop,insertloaction):
    insertContentSql="INSERT INTO "+insertTable+"(image,price,deal,title,shop,location)VALUES(%s,%s,%s,%s,%s,%s)"
#         insertContentSql="INSERT INTO "+insertTable+"(time,title,text,clicks)VALUES("+insertTime+" , "+insertTitle+" , "+insertText+" , "+insertClicks+")"


    DB_insert=connectDB()
    cursor_insert=DB_insert.cursor()
    cursor_insert.execute(insertContentSql,(insertimages,insertprice,insertdeal,inserttitle,insertshop,insertloaction))
    DB_insert.commit()
    DB_insert.close()
    print ('inert contents to  '+insertTable+' successfully')

def main():
    table = creatTable('yh1')
    print('创建表成功')
    total=search(table)
    total=int(re.compile('(\d+)').search(total).group(1))
    for i in range(2,total+1):
        next_page(i,table)
if __name__=='__main__':
    main()

结果展示

image

利用scrapy爬取伯乐在线的所有文章

发表于 2021-07-18 | 分类于 scrapy
字数统计: 1,087 | 阅读时长 ≈ 6

一、首先我们所需要的库

1、resquests
2、re

二、创建一个scrapy

scrapy startproject ArticleSpider

scrapy genspider jobbole www.jobbole.com

三、爬取所有文章列表的url以及爬取下一页

#所要爬取链接的起始url
start_urls = ['http://blog.jobbole.com/all-posts/']

def parse(self, response):
    #获取第一页下的所有a标签
    url_list=response.css('#archive .floated-thumb .post-thumb a')
    for url in url_list:
        #获取img标签下的src属性,图片的链接dizhi
        url_img=url.css('img::attr(src)').extract_first()
        #获取每一个url_list的详情页面的url
        urls=url.xpath('@href')[0].extract()
        #通过parse.urljoin传递一个绝对地址
        #通过meta属性向item中添加font_image_url属性
        yield scrapy.Request(parse.urljoin(response.url,urls),meta={'font_image_url':url_img},callback=self.get_parse)
    #获取下一页的链接地址、
    next=response.css('.next.page-numbers::attr(href)')[0].extract()
    #一直循环,知道没有下一页为止
    if next:
        #回调parse函数
        yield scrapy.Request(parse.urljoin(response.url,next),callback=self.parse)
    else:
        return None

四、对详情文章页面进行分析

    我们要的数据是文章的

[标题,日期,标签,文章,点赞数,收藏数,评论数]

#标题
title= response.css('.grid-8 .entry-header h1::text')[0].extract()
#日期
data=response.css('.grid-8 .entry-meta p::text')[0].extract().strip().replace('·','').strip()
#标签
tag_list = response.css("p.entry-meta-hide-on-mobile a::text").extract()
tag_list = [element for element in tag_list if not element.strip().endswith("评论")]#删除标签内的评论数
tags = ",".join(tag_list)#把标签数组以','链接生成字符串
#文章
article= response.css('.grid-8 .entry')[0].extract()
#点赞数
votetotal=response.css('.post-adds h10::text')[0].extract()
match_re = re.match('.*(\d+).*', votetotal)#用正则筛选出我们所需要的数字
if match_re:
    votetotal=int(match_re.group(1))#返回第一个
else:
    votetotal=0#如国没有则默认为0
#收藏数
bookmark=response.css('.post-adds .bookmark-btn::text')[0].extract()
match_re = re.match('.*(\d+).*', bookmark)
  if match_re:
    bookmark=int(match_re.group(1))
else:
    bookmark=0
#评论数
comments=response.css('.post-adds a .hide-on-480::text')[0].extract()
match_re = re.match('.*(\d+).*', comments)
if match_re:
 comments=int(match_re.group(1))
else:
 comments=0

    get_parse方法来获取详情页的数据

def get_parse(self,response):
    #接收传过来的 font_iamgge_url
    image_url=response.meta.get('font_image_url','')
    title= response.css('.grid-8 .entry-header h1::text')[0].extract()
    data=response.css('.grid-8 .entry-meta p::text')[0].extract().strip().replace('·','').strip()
    category=response.css('.grid-8 .entry-meta p a::text')[0].extract()
    tag=response.css('.grid-8 .entry-meta p a::text')[-1].extract().strip().replace('·','').strip()
    article= response.css('.grid-8 .entry')[0].extract()
    votetotal=response.css('.post-adds h10::text')[0].extract()
    match_re = re.match('.*(\d+).*', votetotal)
    if match_re:
        votetotal=int(match_re.group(1))
    else:
        votetotal=0
    bookmark=response.css('.post-adds .bookmark-btn::text')[0].extract()
    match_re = re.match('.*(\d+).*', bookmark)
    if match_re:
        bookmark=int(match_re.group(1))
    else:
        bookmark=0
    comments=response.css('.post-adds a .hide-on-480::text')[0].extract()
    match_re = re.match('.*(\d+).*', comments)
    if match_re:
        comments=int(match_re.group(1))
    else:
        comments=0
    #对item对象实例化
    item=ArticlespiderItem()
    item['url']=response.url
    #调用md5把url压缩为固定的哈希值
    item['url_object_id'] = get_md5(response.url)
    item['image_url']=[image_url]
    #调用dtaetime库把字符串转化为date属性
    try:
        data=datetime.datetime.strftime(data,"%Y/%m/%d").date()
    except Exception as e:
        #如果有异常就获取当前系统的时间
        data=datetime.datetime.now().date()
    item['data']=data
    item['title'] = title
    item['category'] = category
    item['tag'] = tag
    item['article'] = article
    item['votetotal'] = votetotal
    item['bookmark']=bookmark
    item['comments'] = comments

五、下载每一篇文章的图片

在settings.py文件中加入
#获取item中iamge_url的图片链接
IMAGES_URLS_FIELD='image_url'
#获取当前的文件路径
object_url=os.path.abspath(os.path.dirname(__file__))
#创建image文件夹来存储图片
IMAGES_STORE=os.path.join(object_url,'image')

    在image文件下会自动生成图片的名字,在ImagesPipeline中我们会找到path变量,我们可以找到每个url所对应的图片的名字,把它存到item中

class ArticleImagePipeline(ImagesPipeline):

def item_completed(self, results, item, info):
    if 'image_url' in item:
        for ok,value in results:
            image_file_path=value['path']
        item['image_url_path']=image_file_path
    return item

六、随着以后爬取速度加快,存的速度赶不上爬的速度,导致存的堆积影响性能,所以使用twisted将musql变成异步操作

from twisted.enterprise import adbapi

class MysqlTwistePipline(object):
def __init__(self,dbpool):
    self.dbpool=dbpool
@classmethod
def from_settings(cls,settings):
    dbparms=dict(
        host=settings['MYSQL_HOST'],
        db=settings['MYSQL_DB'] ,
        user=settings['MYSQL_USER'] ,
        passwd=settings['MYSQL_PASSWORD'] ,
        charset='utf8',
        cursorclass=MySQLdb.cursors.DictCursor,
        use_unicode=True,
    )
    dbpool=adbapi.ConnectionPool('MySQLdb',**dbparms)
    return cls(dbpool)

def process_item(self , item , spider):
    #使用twisted将musql变成异步操作
    query=self.dbpool.runInteraction(self.do_insert,item)
    query.addErrback(self.hand_erro)
def hand_erro(self,failure):
    print(failure)
def do_insert(self,cursor,item):
    url = item['url']
    url_object_id = item['url_object_id']
    image_urls = item['image_url']
    image_url = image_urls[0]
    image_url_path = item['image_url_path']
    title = item['title']
    data = item['data']
    category = item['category']
    tag = item['tag']
    article = item['article']
    votetotal = item['votetotal']
    bookmark = item['bookmark']
    comments = item['comments']
    cursor.execute(
        'insert into jobole(title,data,url,url_object_id,image_url,image_url_path,tag,category,article,votetotal,bookmark,comments) values(%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)' ,
        (title , data , url , url_object_id , image_url , image_url_path , tag , category , article , votetotal ,
         bookmark , comments))

爬取房天下的租房信息,并对数据进行可视化展示

发表于 2021-07-18 | 分类于 Scrapy
字数统计: 576 | 阅读时长 ≈ 3

一、首先准备需要的库

1、pandas//是python的一个数据分析包
2、matplotlib//是一个 Python 的 2D绘图库,它以各种硬拷贝格式和跨平台的交互式环境生成出版质量级别的图形。
3、jieba//jieba(结巴)是一个强大的分词库,完美支持中文分词
4、wordcloud//基于Python的词云生成类库
5、numpy//NumPy系统是Python的一种开源的数值计算扩展。这种工具可用来存储和处理大型矩阵,比Python自身的嵌套列表(nested list structure)结构要高效的多(该结构也可以用来表示矩阵(matrix))

二、用scrapy创建一个项目

scrapy startproject zufangSpider

scrapy genspider zufang http://zu.sh.fang.com/cities.aspx

三、实现房天下的的数据爬取

#初始化url
def start_requests(self):
    yield scrapy.Reques(self.city_url,callback=self.get_city)
#调用get_city()方法
 def get_city(self,response):
    url=response.xpath('/html/body/div[3]/div[1]/a/@href').extract()
    #循环热门城市
    for i in url:
        product={
            'city':i
        }
        yield scrapy.Request(product['city'],callback=self.city_parse, dont_filter=True)
        #循环爬取每一页
        for j in range(2,10):
            next_url=product['city']+'house/i3%s'%j
            yield scrapy.Request(next_url,callback=self.city_parse,dont_filter=True)
#调用city_parse()方法获取每一页的数据
def city_parse(self, response):
    zufang = response.xpath('//div[@class="houseList"]')
    for fangzi in zufang:
        title=fangzi.xpath('//p[@class="title"]/a/text()').extract()
        area =fangzi.xpath('//p[@class="gray6 mt20"]/a[1]/span[1]/text()').extract()
        rent_style = fangzi.xpath('//p[@class="font16 mt20 bold"]/text()[1]').extract()
        house_type= fangzi.xpath('//p[@class="font16 mt20 bold"]/text()[2]').extract()
        house_area = fangzi.xpath('//p[@class="font16 mt20 bold"]/text()[3]').extract()
        if fangzi.xpath('//p[@class="font16 mt20 bold"]/text()[4]'):
            orientation = fangzi.xpath('//p[@class="font16 mt20 bold"]/text()[4]').extract()
        else:
            orientation=''
        price = fangzi.xpath('//p[@class="mt5 alingC"]/span/text()').extract()
        for i in range(len(title)):
            item = ZufangScrapyItem()
            item['title']=title[i]
            item['area']=area[i]
            item['rent_style']=rent_style[i].strip()
            item['house_type']=house_type[i]
            item['house_area']=house_area[i]
            item['orientation']=orientation[i].strip()
            item['price']=price[i]
            yield item

四、对数据进行可视化

1、首先运行 scrapy crawl zufang -o zufang.csv

把数据保存成csv文件

2、import pandas as pd
data=pd.read_csv(r'H:\Python\zufang_scrapy\zufang.csv')
data.head()

zufang.csv

3、import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif']=['SimHei']
data['orientation'].value_counts().plot(kind='barh',rot=0)
plt.show()

image

4、final=''
stopword=['NaN']
for n in range(data.shape[0]):
seg_list=list(jieba.cut(data['area'][n]))
for seg in seg_list:
    if seg not in stopword:
        final=final+seg+' '
my_wordcloud=WordCloud(collocations=False,font_path=r'C:\Windows\Fonts\simfang.ttf',width=2000,height=600,margin=2).generate(final)
plt.imshow(my_wordcloud)
plt.axis('off')
plt.show()

image

详细代码:可以访问我的 GitHub 地址

利用scrapy爬取知乎用户信息并存储在mongodb数据库中

发表于 2021-07-18 | 分类于 爬虫
字数统计: 660 | 阅读时长 ≈ 4

一、首先在setting.py中修改True改为False

# Obey robots.txt rules
#允许爬取robots.txt文件内不能爬取的资源
ROBOTSTXT_OBEY = True
#知乎是由反扒措施的必须添加User-agent以及authorization
DEFAULT_REQUEST_HEADERS = {
  'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
  'Accept-Language': 'en',
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.186 Safari/537.36' ,
    'authorization':'Bearer 2|1:0|10:1521707334|4:z_c0|80:MS4xS1NYS0FnQUFBQUFtQUFBQVlBSlZUVWEzb0Z0ZDl0MGhaa0VJOWM0ODhiejhRenVUd0tURnFnPT0=|98bb6f4900c1b4b52ece0282393ede5e31046c9a90216e69dec1feece8086ee0'
}

二、编写spider的项目文件

1、zhihu_user.py

# -*- coding: utf-8 -*-
import json

import scrapy
from scrapy import Spider,Request

from ..items import UserItem


class ZhihuUserSpider(Spider):
    name = 'zhihu_user'
    allowed_domains = ['www.zhihu.com']
    start_urls = ['http://www.zhihu.com/']
    start_user='excited-vczh'
    user_url='https://www.zhihu.com/api/v4/members/{user}?include={include}'
    user_query='allow_message,is_followed,is_following,is_org,is_blocking,employments,answer_count,follower_count,articles_count,gender,badge[?(type=best_answerer)].topics'
    follows_url='https://www.zhihu.com/api/v4/members/{user}/followees?include={include}&offset={offset}&limit={limit}'
    follows_query='data[*].answer_count,articles_count,gender,follower_count,is_followed,is_following,badge[?(type=best_answerer)].topics'
    followers_url='https://www.zhihu.com/api/v4/members/{user}/followers?include={include}&offset={offset}&limit={limit}'
    followers_query='data[*].answer_count,articles_count,gender,follower_count,is_followed,is_following,badge[?(type=best_answerer)].topics'
    def start_requests(self):
        yield Request(self.user_url.format(user=self.start_user,include=self.user_query),self.parse_user)
        yield Request(self.follows_url.format(user=self.start_user,include=self.follows_query,offset=0,limit=20),callback=self.parse_query)
    def parse_user(self, response):
        result=json.loads(response.text)
        item=UserItem()
        for field in item.fields:
            if field in result.keys():
                item[field]=result.get(field)
        yield item
        yield Request(self.follows_url.format(user=result.get('url_token'),include=self.follows_query,offset=0,limit=20),callback=self.parse_query)
        yield Request(self.followers_url.format(user=result.get('url_token'),include=self.followers_query,offset=0,limit=20),callback=self.parse_querys)
    def parse_query(self, response):
        results=json.loads(response.text)
        if 'data' in results.keys():
            for result in results.get('data'):
                yield Request(self.user_url.format(user=result.get('url_token'),include=self.user_query),callback=self.parse_user)
        if 'paging' in results.keys() and results.get('paging').get('is_end')==False:
            next_page=results.get('paging').get('next')
            yield Request(next_page,self.parse_query)
    def parse_querys(self, response):
        results=json.loads(response.text)
        if 'data' in results.keys():
            for result in results.get('data'):
                yield Request(self.user_url.format(user=result.get('url_token'),include=self.user_query),callback=self.parse_user)
        if 'paging' in results.keys() and results.get('paging').get('is_end')==False:
            next_page=results.get('paging').get('next')
            yield Request(next_page,self.parse_querys)

2、items.py

# -*- coding: utf-8 -*-

# Define here the models for your scraped items
#
# See documentation in:
# https://doc.scrapy.org/en/latest/topics/items.html

import scrapy
from scrapy import Item,Field

class UserItem(Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
    headline=Field()
    avatar_url=Field()
    name=Field()
    type=Field()
    url_token=Field()
    user_type=Field()

3、pipelines.py

# -*- coding: utf-8 -*-

# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: https://doc.scrapy.org/en/latest/topics/item-pipeline.html


import pymongo

class MongoPipeline(object):

    collection_name = 'scrapy_items'

    def __init__(self, mongo_uri, mongo_db):
        self.mongo_uri = mongo_uri
        self.mongo_db = mongo_db

    @classmethod
    def from_crawler(cls, crawler):
        return cls(
            mongo_uri=crawler.settings.get('MONGO_URI'),
            mongo_db=crawler.settings.get('MONGO_DATABASE')
        )

    def open_spider(self, spider):
        self.client = pymongo.MongoClient(self.mongo_uri)
        self.db = self.client[self.mongo_db]

    def close_spider(self, spider):
        self.client.close()

    def process_item(self, item, spider):
        self.db['user'].update({'url_token':item['url_token']},{'$set':item},True)
        #self.db[self.collection_name].insert_one(dict(item))
        return item

4、setting.py

BOT_NAME = 'zhihu'

SPIDER_MODULES = ['zhihu.spiders']
NEWSPIDER_MODULE = 'zhihu.spiders'
MONGO_URI='localhost'
MONGO_DATABASE='zhihu'

三、最后启动setting.py中的

ITEM_PIPELINES = {
       'zhihu.pipelines.MongoPipeline': 300,
}
#去掉注释

四、结果展示

image

scrapy爬虫框架的简介

发表于 2021-07-18 | 分类于 scrapy
字数统计: 529 | 阅读时长 ≈ 2

一、安装scrapy所依赖的库

1、安装wheel
    pip install wheel
2、安装lxml
    https://pypi.python.org/pypi/lxml/4.1.0
3、安装pyopenssl
    https://pypi.python.org/pypi/pyOpenSSL/17.5.0
4、安装Twisted
    https://www.lfd.uci.edu/~gohlke/pythonlibs/
5、安装pywin32
    https://sourceforge.net/projects/pywin32/files/
6、安装scrapy
    pip install scrapy

二、爬虫举例

1、创建项目

scrapy startproject zhihu

2、创建spider项目程序

cd zhihu
scrapy genspider zhihuspider www.zhihu.com

3、自动创建目录及文件

image

4、生成的爬虫具有基本的结构,我们可以直接在此基础上编写代码

# -*- coding: utf-8 -*-
import scrapy


class ZhihuSpider(scrapy.Spider):
name = "zhihuspider"
allowed_domains = ["zhihu.com"]
start_urls = ['http://www.zhihu.com/']

def parse(self, response):
    pass

5、然后,可以我们按照name来运行爬虫

scrapy crawl 'zhihuspider'

二、项目文件详细分析

1、spriders文件夹

#项目文件,以后的代码都要在这里写入
zhihuspider.py

2、items.py

from scrapy import Item,Field

class UserItem(Item):
    #Item 对象是种简单的容器,保存了爬取到得数据。 其提供了 类似于词典(dictionary-like) 的API以及用于声明可用字段的简单语法。
    # define the fields for your item here like:
    #爬取所需要的数据的名称在这里定义,很像字典
    # name = scrapy.Field()

3、pipelines.py

        当Item在Spider中被收集之后,它将会被传递到Item Pipeline,一些组件会按照一定的顺序执行对Item的处理

###主要是处理以下4点任务

1.清理HTML数据

2.验证爬取的数据(检查item包含某些字段)

3.查重(并丢弃)

4.将爬取结果保存到数据库中

#存到mogodb数据库

import pymongo

class MongoPipeline(object):

    collection_name = 'scrapy_items'

    def __init__(self, mongo_uri, mongo_db):
        self.mongo_uri = mongo_uri
        self.mongo_db = mongo_db

    @classmethod
    def from_crawler(cls, crawler):
        return cls(
            mongo_uri=crawler.settings.get('MONGO_URI'),
            mongo_db=crawler.settings.get('MONGO_DATABASE', 'items')
        )

    def open_spider(self, spider):
        self.client = pymongo.MongoClient(self.mongo_uri)
        self.db = self.client[self.mongo_db]

    def close_spider(self, spider):
        self.client.close()

    def process_item(self, item, spider):
        self.db[self.collection_name].insert_one(dict(item))
        return item

4、settings.py

        用于设置常量的,例如 mongodb 的 url 和 database

BOT_NAME = 'zhihu'

SPIDER_MODULES = ['zhihu.spiders']

NEWSPIDER_MODULE = 'zhihu.spiders'

MONGO_URI='localhost'

MONGO_DATABASE='zhihu'

#默认是True的这个变量是用来是否爬robot文件的改为False是允许的意思
ROBOTSTXT_OBEY = True

python爬虫的精华篇

发表于 2021-07-18 | 分类于 爬虫
字数统计: 1,447 | 阅读时长 ≈ 5

最简单的反爬手段

        有一部分网站(甚至包括部分商业网站)其实并没有真正认真做过反爬虫这件事情,你不需要做任何伪装,即可分分钟抓光它的网站。面对这样的网站,你只需要开大马力抓抓抓就好了,如果处于情怀考虑,你可以抓的慢一点,让它的服务器别太累。

        除去这样的情况,最简单的反爬虫机制,应该算是U-A校验了。浏览器在发送请求的时候,会附带一部分浏览器及当前系统环境的参数给服务器,这部分数据放在HTTP请求的header部分。

通过访问频度反爬

        这种反爬虫机制的原理是,真人通过浏览器访问网站的速度(相对程序来讲)是很慢的,所以如果你一秒访问了200个页面——这里不代表实际数值,只是表达在较短时间内发送了较多请求,具体阈值需要具体考虑——服务器则认为你是一个爬虫。

适用情况:限制频率情况。

Requests,Urllib2都可以使用time库的sleep()函数:

import time
time.sleep(1)

通过验证码限制

        这样的方式与上面的方式相比更加难处理的是,不管你的访问频次怎么样,你都需要输入验证码才行。比如12306,不管你是登录还是购票,也不论你是第一次还是第一万次购买,你都需要输入一个验证码之后才能继续。这时候,在绝大部分情况下,你必须要想办法识别验证码了。之所以说是大多数情况下,是因为在极少数极少数情况下(尤其是政府网站),棒槌程序员通过客户端的JavaScript来校验验证码,这时候对你的爬虫来讲,其实是没有验证码的(比如中国商标网)。除开你遇到这种几乎可以忽略不计的棒槌开发的网站,其他时候你只有通过识别验证码来继续后面的操作了。

1、首先你可以找到验证吗图片的url
2、把图片保存到本地,然后手动输入验证码达到验证的效果,可以参考我前面的文章,有关豆瓣验证码的处理

通过经常变换网页结构

        常见于一些社交网站,他们会经常更换网页的结构,如果你是通过依赖网页结构来解析需要的数据(不幸的是大部分情况下我们都需要通过网页结构来解析需要的数据),则在原本的网页位置找不到原本需要的内容。这时候,要分不同情况具体处理了。如果你只打算一次性抓取特定数据,那么赶快行动,它以后结构变了无所谓,反正你也不打算在抓它一次。如果是需要持续性抓取的网站,就要仔细思考下应对方案了。一个简单粗暴但是比较费力的办法是,写一个校验脚本,定期校验网页结构,如果与预期不符,那么赶快通知自己(或者特定开发者)修改解析部分,以应对网页结构变化。

对于Ajax请求的处理

        对于“加载更多”情况,使用Ajax来传输很多数据。它的工作原理是:从网页的url加载网页的源代码之后,会在浏览器里执行JavaScript程序。这些程序会加载更多的内容,“填充”到网页里。这就是为什么如果你直接去爬网页本身的url,你会找不到页面的实际内容。这里,若使用Google Chrome分析”请求“对应的链接(方法:右键→审查元素→Network→清空,点击”加载更多“,出现对应的GET链接寻找Type为text/html的,点击,查看get参数或者复制Request URL),循环过程。

自动化测试工具Selenium

        Selenium是一款自动化测试工具。它能实现操纵浏览器,包括字符填充、鼠标点击、获取元素、页面切换等一系列操作。总之,凡是浏览器能做的事,Selenium都能够做到。

使用代理

        适用情况:限制IP地址情况,也可解决由于“频繁点击”而需要输入验证码登陆的情况。
这种情况最好的办法就是维护一个代理IP池,网上有很多免费的代理IP,良莠不齐,可以通过筛选找到能用的。对于“频繁点击”的情况,我们还可以通过限制爬虫访问网站的频率来避免被网站禁掉。

    proxies = {'http':'http://XX.XX.XX.XX:XXXX'}
    Requests://强烈推荐使用
    import requests
    response = requests.get(url=url, proxies=proxies)
    Urllib2:
    import urllib2
    proxy_support = urllib2.ProxyHandler(proxies)
    opener = urllib2.build_opener(proxy_support, urllib2.HTTPHandler)
    urllib2.install_opener(opener) # 安装opener,此后调用urlopen()时都会使用安装过的opener对象
    response = urllib2.urlopen(url)

多线程

        由于Python的是跨平台的,自然也应该提供一个跨平台的多进程支持。multiprocessing模块就是跨平台版本的多进程模块。
multiprocessing提供模块一个了Process类来代表一个进程对象,下面的例子演示了启动一个子进程并等待其结束:
from multiprocessing import Process
import os

#子进程要执行的代码
def run_proc(name):
    print 'Run child process %s (%s)...' % (name, os.getpid())

if __name__=='__main__':
    print 'Parent process %s.' % os.getpid()
    p = Process(target=run_proc, args=('test',))
    print 'Process will start.'
    p.start()
    p.join()
    print 'Process end.'

执行结果如下:

Parent process 928.
Process will start.
Run child process test (929)...
Process end.

参考 廖雪峰 的python教程

<i class="fa fa-angle-left"></i>123…5<i class="fa fa-angle-right"></i>

44 日志
14 分类
38 标签
RSS
GitHub E-Mail ZhiHu
推荐阅读
  • 静觅
  • 廖雪峰python教程
  • stormzhang
  • Howiezhao
  • PyZh
  • Python最佳实践指南
  • 敖丙
  • Top K
© 2024 TomorrowLi
本站访客数:
由 Hexo 强力驱动
|
主题 — NexT.Mist v5.1.3
博客全站共23.3k字